All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TrackRefinementBaseAlgorithm.cc
Go to the documentation of this file.
1 /**
2  * @file larpandoracontent/LArTwoDReco/LArCosmicRay/TrackRefinementBaseAlgorithm.cc
3  *
4  * @brief Implementation of the track refinement base class.
5  *
6  * $Log: $
7  */
8 #include "Pandora/AlgorithmHeaders.h"
9 
11 
15 
16 using namespace pandora;
17 
18 namespace lar_content
19 {
20 
21 TrackRefinementBaseAlgorithm::TrackRefinementBaseAlgorithm() :
22  m_minClusterLength(15.f),
23  m_microSlidingFitWindow(20),
24  m_macroSlidingFitWindow(1000),
25  m_stableRegionClusterFraction(0.05f),
26  m_mergePointMinCosAngleDeviation(0.999f),
27  m_minHitFractionForHitRemoval(0.05f),
28  m_maxDistanceFromMainTrack(0.75f),
29  m_maxHitDistanceFromCluster(4.f),
30  m_maxHitSeparationForConnectedCluster(4.f),
31  m_maxTrackGaps(3),
32  m_lineSegmentLength(3.f),
33  m_hitWidthMode(false)
34 {
35 }
36 
37 //------------------------------------------------------------------------------------------------------------------------------------------
38 
39 template <typename T>
40 void TrackRefinementBaseAlgorithm::InitialiseContainers(const ClusterList *pClusterList, const T sortFunction, ClusterVector &clusterVector,
41  SlidingFitResultMapPair &slidingFitResultMapPair) const
42 {
43  const float slidingFitPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
44 
45  for (const Cluster *const pCluster : *pClusterList)
46  {
48  continue;
49 
50  try
51  {
52  const TwoDSlidingFitResult microSlidingFitResult(pCluster, m_microSlidingFitWindow, slidingFitPitch);
53  const TwoDSlidingFitResult macroSlidingFitResult(pCluster, m_macroSlidingFitWindow, slidingFitPitch);
54 
55  slidingFitResultMapPair.first->insert(TwoDSlidingFitResultMap::value_type(pCluster, microSlidingFitResult));
56  slidingFitResultMapPair.second->insert(TwoDSlidingFitResultMap::value_type(pCluster, macroSlidingFitResult));
57  clusterVector.push_back(pCluster);
58  }
59  catch (const StatusCodeException &)
60  {
61  }
62  }
63 
64  std::sort(clusterVector.begin(), clusterVector.end(), sortFunction);
65 }
66 
67 //------------------------------------------------------------------------------------------------------------------------------------------
68 
70  const TwoDSlidingFitResult &clusterMacroFitResult, const TwoDSlidingFitResult &associatedMacroFitResult, const bool isEndUpstream,
71  CartesianVector &clusterMergePosition, CartesianVector &clusterMergeDirection) const
72 {
73  CartesianVector clusterAverageDirection(0.f, 0.f, 0.f), associatedAverageDirection(0.f, 0.f, 0.f);
74  clusterMacroFitResult.GetGlobalDirection(clusterMacroFitResult.GetLayerFitResultMap().begin()->second.GetGradient(), clusterAverageDirection);
75  associatedMacroFitResult.GetGlobalDirection(associatedMacroFitResult.GetLayerFitResultMap().begin()->second.GetGradient(), associatedAverageDirection);
76 
77  const LayerFitResultMap &clusterMicroLayerFitResultMap(clusterMicroFitResult.GetLayerFitResultMap());
78  const int startLayer(isEndUpstream ? clusterMicroFitResult.GetMinLayer() : clusterMicroFitResult.GetMaxLayer());
79  const int endLayer(isEndUpstream ? clusterMicroFitResult.GetMaxLayer() : clusterMicroFitResult.GetMinLayer());
80  const int loopTerminationLayer(endLayer + (isEndUpstream ? 1 : -1));
81  const int step(isEndUpstream ? 1 : -1);
82 
83  // ATTN: Search for stable region for which the local layer gradient agrees well with associated cluster global gradient
84  unsigned int gradientStabilityWindow(std::ceil(clusterMicroLayerFitResultMap.size() * m_stableRegionClusterFraction));
85  unsigned int goodLayerCount(0);
86 
87  clusterMicroLayerFitResultMap.at(endLayer);
88 
89  for (int i = startLayer; i != loopTerminationLayer; i += step)
90  {
91  const auto microIter(clusterMicroLayerFitResultMap.find(i));
92 
93  if (microIter == clusterMicroLayerFitResultMap.end())
94  continue;
95 
96  CartesianVector microDirection(0.f, 0.f, 0.f);
97  clusterMicroFitResult.GetGlobalDirection(microIter->second.GetGradient(), microDirection);
98 
99  const float cosDirectionOpeningAngle(microDirection.GetCosOpeningAngle(associatedAverageDirection));
100  if (cosDirectionOpeningAngle > m_mergePointMinCosAngleDeviation)
101  {
102  // ATTN: Set merge point and direction as that at the first layer in the stable region
103  if (goodLayerCount == 0)
104  {
105  clusterMergeDirection = clusterAverageDirection;
106  PANDORA_THROW_RESULT_IF(
107  STATUS_CODE_SUCCESS, !=, clusterMicroFitResult.GetGlobalFitPosition(microIter->second.GetL(), clusterMergePosition));
108  }
109 
110  ++goodLayerCount;
111  }
112  else
113  {
114  goodLayerCount = 0;
115  }
116 
117  if (goodLayerCount > gradientStabilityWindow)
118  break;
119 
120  // ATTN: Abort merging process have not found a stable region
121  if (i == endLayer)
122  return false;
123  }
124 
125  return true;
126 }
127 
128 //------------------------------------------------------------------------------------------------------------------------------------------
129 
130 void TrackRefinementBaseAlgorithm::GetHitsInBoundingBox(const CartesianVector &firstCorner, const CartesianVector &secondCorner,
131  const ClusterList *const pClusterList, ClusterToCaloHitListMap &clusterToCaloHitListMap,
132  const ClusterList &unavailableProtectedClusters, const float distanceToLine) const
133 {
134  const float minX(std::min(firstCorner.GetX(), secondCorner.GetX())), maxX(std::max(firstCorner.GetX(), secondCorner.GetX()));
135  const float minZ(std::min(firstCorner.GetZ(), secondCorner.GetZ())), maxZ(std::max(firstCorner.GetZ(), secondCorner.GetZ()));
136 
137  CartesianVector connectingLineDirection(firstCorner - secondCorner);
138  connectingLineDirection = connectingLineDirection.GetUnitVector();
139 
140  for (const Cluster *const pCluster : *pClusterList)
141  {
142  if (std::find(unavailableProtectedClusters.begin(), unavailableProtectedClusters.end(), pCluster) != unavailableProtectedClusters.end())
143  continue;
144 
145  const OrderedCaloHitList &orderedCaloHitList(pCluster->GetOrderedCaloHitList());
146  for (const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
147  {
148  for (const CaloHit *const pCaloHit : *mapEntry.second)
149  {
150  CartesianVector hitPosition(m_hitWidthMode ? LArHitWidthHelper::GetClosestPointToLine2D(firstCorner, connectingLineDirection, pCaloHit)
151  : pCaloHit->GetPositionVector());
152 
153  if (!this->IsInBoundingBox(minX, maxX, minZ, maxZ, hitPosition))
154  continue;
155 
156  if (distanceToLine > 0.f)
157  {
158  if (!this->IsCloseToLine(hitPosition, firstCorner, connectingLineDirection, distanceToLine))
159  continue;
160  }
161 
162  clusterToCaloHitListMap[pCluster].push_back(pCaloHit);
163  }
164  }
165  }
166 }
167 
168 //------------------------------------------------------------------------------------------------------------------------------------------
169 
171  const float minX, const float maxX, const float minZ, const float maxZ, const CartesianVector &hitPosition) const
172 {
173  return !((hitPosition.GetX() < minX) || (hitPosition.GetX() > maxX) || (hitPosition.GetZ() < minZ) || (hitPosition.GetZ() > maxZ));
174 }
175 
176 //------------------------------------------------------------------------------------------------------------------------------------------
177 
178 bool TrackRefinementBaseAlgorithm::IsCloseToLine(const CartesianVector &hitPosition, const CartesianVector &lineStart,
179  const CartesianVector &lineDirection, const float distanceToLine) const
180 {
181  const float transverseDistanceFromLine(lineDirection.GetCrossProduct(hitPosition - lineStart).GetMagnitude());
182 
183  return (transverseDistanceFromLine < distanceToLine);
184 }
185 
186 //------------------------------------------------------------------------------------------------------------------------------------------
187 
188 bool TrackRefinementBaseAlgorithm::AreExtrapolatedHitsGood(const ClusterToCaloHitListMap &clusterToCaloHitListMap, ClusterAssociation &clusterAssociation) const
189 {
190  CaloHitVector extrapolatedHitVector;
191  for (const auto &entry : clusterToCaloHitListMap)
192  extrapolatedHitVector.insert(extrapolatedHitVector.begin(), entry.second.begin(), entry.second.end());
193 
194  // ATTN: Extrapolated hit checks require extrapolatedHitVector to be ordered from upstream -> downstream merge point
195  std::sort(extrapolatedHitVector.begin(), extrapolatedHitVector.end(),
196  SortByDistanceAlongLine(clusterAssociation.GetUpstreamMergePoint(), clusterAssociation.GetConnectingLineDirection(), m_hitWidthMode));
197 
198  if (!this->AreExtrapolatedHitsNearBoundaries(extrapolatedHitVector, clusterAssociation))
199  return false;
200 
201  if (clusterToCaloHitListMap.empty())
202  return true;
203 
204  if (!this->IsTrackContinuous(clusterAssociation, extrapolatedHitVector))
205  return false;
206 
207  return true;
208 }
209 
210 //------------------------------------------------------------------------------------------------------------------------------------------
211 
212 bool TrackRefinementBaseAlgorithm::IsNearBoundary(const CaloHit *const pCaloHit, const CartesianVector &boundaryPosition2D, const float boundaryTolerance) const
213 {
214  const float distanceToBoundary(LArHitWidthHelper::GetClosestDistanceToPoint2D(pCaloHit, boundaryPosition2D));
215 
216  return (distanceToBoundary < boundaryTolerance);
217 }
218 
219 //------------------------------------------------------------------------------------------------------------------------------------------
220 
221 bool TrackRefinementBaseAlgorithm::IsTrackContinuous(const ClusterAssociation &clusterAssociation, const CaloHitVector &extrapolatedCaloHitVector) const
222 {
223  CartesianPointVector trackSegmentBoundaries;
224  this->GetTrackSegmentBoundaries(clusterAssociation, trackSegmentBoundaries);
225 
226  if (trackSegmentBoundaries.size() < 2)
227  {
228  std::cout << "TrackInEMShowerAlgorithm: Less than two track segment boundaries" << std::endl;
229  throw STATUS_CODE_NOT_ALLOWED;
230  }
231 
232  unsigned int segmentsWithoutHits(0);
233  CaloHitVector::const_iterator caloHitIter(extrapolatedCaloHitVector.begin());
234  CartesianVector hitPosition(m_hitWidthMode ? LArHitWidthHelper::GetClosestPointToLine2D(clusterAssociation.GetUpstreamMergePoint(),
235  clusterAssociation.GetConnectingLineDirection(), *caloHitIter)
236  : (*caloHitIter)->GetPositionVector());
237 
238  for (unsigned int i = 0; i < (trackSegmentBoundaries.size() - 1); ++i)
239  {
240  if (caloHitIter == extrapolatedCaloHitVector.end())
241  {
242  ++segmentsWithoutHits;
243 
244  if (segmentsWithoutHits > m_maxTrackGaps)
245  return false;
246 
247  continue;
248  }
249 
250  unsigned int hitsInSegment(0);
251  while (this->IsInLineSegment(trackSegmentBoundaries.at(i), trackSegmentBoundaries.at(i + 1), hitPosition))
252  {
253  ++hitsInSegment;
254  ++caloHitIter;
255 
256  if (caloHitIter == extrapolatedCaloHitVector.end())
257  break;
258 
260  clusterAssociation.GetConnectingLineDirection(), *caloHitIter)
261  : (*caloHitIter)->GetPositionVector();
262  }
263 
264  segmentsWithoutHits = hitsInSegment ? 0 : segmentsWithoutHits + 1;
265 
266  if (segmentsWithoutHits > m_maxTrackGaps)
267  return false;
268  }
269 
270  return true;
271 }
272 
273 //------------------------------------------------------------------------------------------------------------------------------------------
274 
275 void TrackRefinementBaseAlgorithm::GetTrackSegmentBoundaries(const ClusterAssociation &clusterAssociation, CartesianPointVector &trackSegmentBoundaries) const
276 {
277  if (m_lineSegmentLength < std::numeric_limits<float>::epsilon())
278  {
279  std::cout << "TrackInEMShowerAlgorithm: Line segment length must be positive and nonzero" << std::endl;
280  throw STATUS_CODE_INVALID_PARAMETER;
281  }
282 
283  const CartesianVector &trackDirection(clusterAssociation.GetConnectingLineDirection());
284  float trackLength((clusterAssociation.GetUpstreamMergePoint() - clusterAssociation.GetDownstreamMergePoint()).GetMagnitude());
285 
286  // ATTN: Consider the existence of gaps where no hits will be found
287  DetectorGapList consideredGaps;
288  trackLength -= this->DistanceInGap(
289  clusterAssociation.GetUpstreamMergePoint(), clusterAssociation.GetDownstreamMergePoint(), trackDirection, consideredGaps);
290  consideredGaps.clear();
291 
292  const int fullSegments(std::floor(trackLength / m_lineSegmentLength));
293 
294  if (fullSegments == 0)
295  {
296  trackSegmentBoundaries = {clusterAssociation.GetUpstreamMergePoint(), clusterAssociation.GetDownstreamMergePoint()};
297  return;
298  }
299 
300  // ATTN: To handle final segment merge track remainder with preceding segment and if track remainder was more than half of the segment length split into two
301  const float lengthOfTrackRemainder(trackLength - (fullSegments * m_lineSegmentLength));
302  const bool splitFinalSegment(lengthOfTrackRemainder > m_lineSegmentLength * 0.5f);
303  const int numberOfBoundaries(fullSegments + (splitFinalSegment ? 2 : 1));
304 
305  CartesianVector segmentUpstreamBoundary(clusterAssociation.GetUpstreamMergePoint()), segmentDownstreamBoundary(segmentUpstreamBoundary);
306  this->RepositionIfInGap(trackDirection, segmentUpstreamBoundary);
307  trackSegmentBoundaries.push_back(segmentUpstreamBoundary);
308 
309  for (int i = 1; i < numberOfBoundaries; ++i)
310  {
311  if (i < fullSegments)
312  {
313  segmentDownstreamBoundary += trackDirection * m_lineSegmentLength;
314  }
315  else
316  {
317  if (splitFinalSegment)
318  {
319  segmentDownstreamBoundary += trackDirection * (m_lineSegmentLength + lengthOfTrackRemainder) * 0.5f;
320  }
321  else
322  {
323  segmentDownstreamBoundary += trackDirection * (m_lineSegmentLength + lengthOfTrackRemainder);
324  }
325  }
326 
327  float distanceInGap(this->DistanceInGap(segmentUpstreamBoundary, segmentDownstreamBoundary, trackDirection, consideredGaps));
328  while (distanceInGap > std::numeric_limits<float>::epsilon())
329  {
330  this->RepositionIfInGap(trackDirection, segmentDownstreamBoundary);
331  segmentDownstreamBoundary += trackDirection * distanceInGap;
332  distanceInGap = this->DistanceInGap(segmentUpstreamBoundary, segmentDownstreamBoundary, trackDirection, consideredGaps);
333  }
334 
335  trackSegmentBoundaries.push_back(segmentDownstreamBoundary);
336  }
337 }
338 
339 //------------------------------------------------------------------------------------------------------------------------------------------
340 
341 void TrackRefinementBaseAlgorithm::RepositionIfInGap(const CartesianVector &mergeDirection, CartesianVector &trackPoint) const
342 {
343  const DetectorGapList detectorGapList(this->GetPandora().GetGeometry()->GetDetectorGapList());
344  for (const DetectorGap *const pDetectorGap : detectorGapList)
345  {
346  const LineGap *const pLineGap(dynamic_cast<const LineGap *>(pDetectorGap));
347 
348  if (pLineGap)
349  {
350  const LineGapType lineGapType(pLineGap->GetLineGapType());
351 
352  if (lineGapType == TPC_DRIFT_GAP)
353  {
354  if ((pLineGap->GetLineStartX() < trackPoint.GetX()) && (pLineGap->GetLineEndX() > trackPoint.GetX()))
355  {
356  if (std::fabs(mergeDirection.GetX()) < std::numeric_limits<float>::epsilon())
357  throw StatusCodeException(STATUS_CODE_FAILURE);
358 
359  const float gradient(mergeDirection.GetZ() / mergeDirection.GetX());
360 
361  trackPoint = CartesianVector(
362  pLineGap->GetLineEndX(), 0.f, trackPoint.GetZ() + (gradient * (pLineGap->GetLineEndX() - trackPoint.GetX())));
363  }
364  }
365 
366  if ((lineGapType == TPC_WIRE_GAP_VIEW_U) || (lineGapType == TPC_WIRE_GAP_VIEW_V) || (lineGapType == TPC_WIRE_GAP_VIEW_W))
367  {
368  if ((pLineGap->GetLineStartZ() < trackPoint.GetZ()) && (pLineGap->GetLineEndZ() > trackPoint.GetZ()))
369  {
370  if (std::fabs(mergeDirection.GetZ()) < std::numeric_limits<float>::epsilon())
371  throw StatusCodeException(STATUS_CODE_FAILURE);
372 
373  const float gradient(mergeDirection.GetX() / mergeDirection.GetZ());
374 
375  trackPoint = CartesianVector(
376  trackPoint.GetX() + (gradient * (pLineGap->GetLineEndZ() - trackPoint.GetZ())), 0.f, pLineGap->GetLineEndZ());
377  }
378  }
379  }
380  }
381 }
382 
383 //------------------------------------------------------------------------------------------------------------------------------------------
384 
385 float TrackRefinementBaseAlgorithm::DistanceInGap(const CartesianVector &upstreamPoint, const CartesianVector &downstreamPoint,
386  const CartesianVector &connectingLine, DetectorGapList &consideredGaps) const
387 {
388  const CartesianVector &lowerXPoint(upstreamPoint.GetX() < downstreamPoint.GetX() ? upstreamPoint : downstreamPoint);
389  const CartesianVector &higherXPoint(upstreamPoint.GetX() < downstreamPoint.GetX() ? downstreamPoint : upstreamPoint);
390 
391  const float cosAngleToX(std::fabs(connectingLine.GetDotProduct(CartesianVector(1.f, 0.f, 0.f))));
392  const float cosAngleToZ(std::fabs(connectingLine.GetDotProduct(CartesianVector(0.f, 0.f, 1.f))));
393 
394  float distanceInGaps(0.f);
395  const DetectorGapList detectorGapList(this->GetPandora().GetGeometry()->GetDetectorGapList());
396  for (const DetectorGap *const pDetectorGap : detectorGapList)
397  {
398  if (std::find(consideredGaps.begin(), consideredGaps.end(), pDetectorGap) != consideredGaps.end())
399  continue;
400 
401  const LineGap *const pLineGap(dynamic_cast<const LineGap *>(pDetectorGap));
402 
403  if (pLineGap)
404  {
405  const LineGapType lineGapType(pLineGap->GetLineGapType());
406 
407  if (lineGapType == TPC_DRIFT_GAP)
408  {
409  float xDistanceInGap(0.f);
410 
411  if ((pLineGap->GetLineStartX() > lowerXPoint.GetX()) && (pLineGap->GetLineEndX() < higherXPoint.GetX()))
412  {
413  xDistanceInGap = (pLineGap->GetLineEndX() - pLineGap->GetLineStartX());
414  }
415  else if ((pLineGap->GetLineStartX() < lowerXPoint.GetX()) && (pLineGap->GetLineEndX() > lowerXPoint.GetX()))
416  {
417  xDistanceInGap = (pLineGap->GetLineEndX() - lowerXPoint.GetX());
418  }
419  else if ((pLineGap->GetLineStartX() < higherXPoint.GetX()) && (pLineGap->GetLineEndX() > higherXPoint.GetX()))
420  {
421  xDistanceInGap = (higherXPoint.GetX() - pLineGap->GetLineStartX());
422  }
423  else
424  {
425  continue;
426  }
427 
428  if (std::fabs(cosAngleToX) < std::numeric_limits<float>::epsilon())
429  throw StatusCodeException(STATUS_CODE_FAILURE);
430 
431  distanceInGaps += (xDistanceInGap / cosAngleToX);
432 
433  consideredGaps.push_back(pDetectorGap);
434  }
435 
436  if ((lineGapType == TPC_WIRE_GAP_VIEW_U) || (lineGapType == TPC_WIRE_GAP_VIEW_V) || (lineGapType == TPC_WIRE_GAP_VIEW_W))
437  {
438  float zDistanceInGap(0.f);
439 
440  if ((pLineGap->GetLineStartZ() > upstreamPoint.GetZ()) && (pLineGap->GetLineEndZ() < downstreamPoint.GetZ()))
441  {
442  zDistanceInGap = pLineGap->GetLineEndZ() - pLineGap->GetLineStartZ();
443  }
444  else if ((pLineGap->GetLineStartZ() < upstreamPoint.GetZ()) && (pLineGap->GetLineEndZ() > upstreamPoint.GetZ()))
445  {
446  zDistanceInGap = pLineGap->GetLineEndZ() - upstreamPoint.GetZ();
447  }
448  else if ((pLineGap->GetLineStartZ() < downstreamPoint.GetZ()) && (pLineGap->GetLineEndZ() > downstreamPoint.GetZ()))
449  {
450  zDistanceInGap = downstreamPoint.GetZ() - pLineGap->GetLineStartZ();
451  }
452  else
453  {
454  continue;
455  }
456 
457  if (std::fabs(cosAngleToZ) < std::numeric_limits<float>::epsilon())
458  throw StatusCodeException(STATUS_CODE_FAILURE);
459 
460  distanceInGaps += (zDistanceInGap / cosAngleToZ);
461 
462  consideredGaps.push_back(pDetectorGap);
463  }
464  }
465  }
466 
467  return distanceInGaps;
468 }
469 
470 //------------------------------------------------------------------------------------------------------------------------------------------
471 
473  const CartesianVector &lowerBoundary, const CartesianVector &upperBoundary, const CartesianVector &point) const
474 {
475  const float segmentBoundaryGradient = (-1.f) * (upperBoundary.GetX() - lowerBoundary.GetX()) / (upperBoundary.GetZ() - lowerBoundary.GetZ());
476  const float xPointOnUpperLine((point.GetZ() - upperBoundary.GetZ()) / segmentBoundaryGradient + upperBoundary.GetX());
477  const float xPointOnLowerLine((point.GetZ() - lowerBoundary.GetZ()) / segmentBoundaryGradient + lowerBoundary.GetX());
478 
479  if (std::fabs(xPointOnUpperLine - point.GetX()) < std::numeric_limits<float>::epsilon())
480  return true;
481 
482  if (std::fabs(xPointOnLowerLine - point.GetX()) < std::numeric_limits<float>::epsilon())
483  return true;
484 
485  if ((point.GetX() > xPointOnUpperLine) && (point.GetX() > xPointOnLowerLine))
486  return false;
487 
488  if ((point.GetX() < xPointOnUpperLine) && (point.GetX() < xPointOnLowerLine))
489  return false;
490 
491  return true;
492 }
493 
494 //------------------------------------------------------------------------------------------------------------------------------------------
495 
496 const Cluster *TrackRefinementBaseAlgorithm::RemoveOffAxisHitsFromTrack(const Cluster *const pCluster, const CartesianVector &splitPosition,
497  const bool isEndUpstream, const ClusterToCaloHitListMap &clusterToCaloHitListMap, ClusterList &remnantClusterList,
498  TwoDSlidingFitResultMap &microSlidingFitResultMap, TwoDSlidingFitResultMap &macroSlidingFitResultMap) const
499 {
500  float rL(0.f), rT(0.f);
501  const TwoDSlidingFitResult &microFitResult(microSlidingFitResultMap.at(pCluster));
502  microFitResult.GetLocalPosition(splitPosition, rL, rT);
503 
504  const TwoDSlidingFitResult &macroFitResult(macroSlidingFitResultMap.at(pCluster));
505  CartesianVector averageDirection(0.f, 0.f, 0.f);
506  macroFitResult.GetGlobalDirection(macroFitResult.GetLayerFitResultMap().begin()->second.GetGradient(), averageDirection);
507 
508  const bool isVertical(std::fabs(averageDirection.GetX()) < std::numeric_limits<float>::epsilon());
509  const float clusterGradient(isVertical ? 0.f : averageDirection.GetZ() / averageDirection.GetX());
510  const float clusterIntercept(isVertical ? splitPosition.GetX() : splitPosition.GetZ() - (clusterGradient * splitPosition.GetX()));
511 
512  // Fragmentation initialisation
513  std::string originalListName, fragmentListName;
514  const ClusterList originalClusterList(1, pCluster);
515  PANDORA_THROW_RESULT_IF(
516  STATUS_CODE_SUCCESS, !=, PandoraContentApi::InitializeFragmentation(*this, originalClusterList, originalListName, fragmentListName));
517 
518  const Cluster *pMainTrackCluster(nullptr), *pAboveCluster(nullptr), *pBelowCluster(nullptr);
519 
520  const OrderedCaloHitList &orderedCaloHitList(pCluster->GetOrderedCaloHitList());
521  for (const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
522  {
523  for (const CaloHit *const pCaloHit : *mapEntry.second)
524  {
525  const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
526  float thisL(0.f), thisT(0.f);
527 
528  microFitResult.GetLocalPosition(pCaloHit->GetPositionVector(), thisL, thisT);
529 
530  bool isAnExtrapolatedHit(false);
531  const auto extrapolatedCaloHitIter(clusterToCaloHitListMap.find(pCluster));
532 
533  if (extrapolatedCaloHitIter != clusterToCaloHitListMap.end())
534  isAnExtrapolatedHit = std::find(extrapolatedCaloHitIter->second.begin(), extrapolatedCaloHitIter->second.end(), pCaloHit) !=
535  extrapolatedCaloHitIter->second.end();
536 
537  const bool isAbove(((clusterGradient * hitPosition.GetX()) + clusterIntercept) < (isVertical ? hitPosition.GetX() : hitPosition.GetZ()));
538  const bool isToRemove(!isAnExtrapolatedHit && (((thisL < rL) && isEndUpstream) || ((thisL > rL) && !isEndUpstream)));
539 
540  const Cluster *&pClusterToModify(isToRemove ? (isAbove ? pAboveCluster : pBelowCluster) : pMainTrackCluster);
541 
542  if (pClusterToModify)
543  {
544  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*this, pClusterToModify, pCaloHit));
545  }
546  else
547  {
549  parameters.m_caloHitList.push_back(pCaloHit);
550  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*this, parameters, pClusterToModify));
551 
552  if (pClusterToModify != pMainTrackCluster)
553  remnantClusterList.push_back(pClusterToModify);
554  }
555  }
556  }
557 
558  // End fragmentation
559  if (pAboveCluster || pBelowCluster)
560  {
561  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*this, fragmentListName, originalListName));
562  return pMainTrackCluster;
563  }
564  else
565  {
566  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*this, originalListName, fragmentListName));
567  return pCluster;
568  }
569 }
570 
571 //------------------------------------------------------------------------------------------------------------------------------------------
572 
573 void TrackRefinementBaseAlgorithm::AddHitsToMainTrack(const Cluster *const pMainTrackCluster, const Cluster *const pShowerCluster,
574  const CaloHitList &caloHitsToMerge, const ClusterAssociation &clusterAssociation, ClusterList &remnantClusterList) const
575 {
576  // To ignore crossing CR muon or test beam tracks
577  if (((static_cast<float>(caloHitsToMerge.size()) / static_cast<float>(pShowerCluster->GetNCaloHits())) < m_minHitFractionForHitRemoval) &&
579  return;
580 
581  if (pShowerCluster->GetNCaloHits() == caloHitsToMerge.size())
582  {
583  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*this, pMainTrackCluster, pShowerCluster));
584  return;
585  }
586 
587  // Fragmentation initialisation
588  std::string originalListName, fragmentListName;
589  const ClusterList originalClusterList(1, pShowerCluster);
590  PANDORA_THROW_RESULT_IF(
591  STATUS_CODE_SUCCESS, !=, PandoraContentApi::InitializeFragmentation(*this, originalClusterList, originalListName, fragmentListName));
592 
593  const Cluster *pAboveCluster(nullptr), *pBelowCluster(nullptr);
594 
595  const bool isVertical(std::fabs(clusterAssociation.GetConnectingLineDirection().GetX()) < std::numeric_limits<float>::epsilon());
596  const float connectingLineGradient(
597  isVertical ? 0.f : clusterAssociation.GetConnectingLineDirection().GetZ() / clusterAssociation.GetConnectingLineDirection().GetX());
598  const float connectingLineIntercept(isVertical ? clusterAssociation.GetUpstreamMergePoint().GetX()
599  : clusterAssociation.GetUpstreamMergePoint().GetZ() -
600  (connectingLineGradient * clusterAssociation.GetUpstreamMergePoint().GetX()));
601 
602  const OrderedCaloHitList orderedCaloHitList(pShowerCluster->GetOrderedCaloHitList());
603  for (const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
604  {
605  for (const CaloHit *const pCaloHit : *mapEntry.second)
606  {
607  const bool isAnExtrapolatedHit(std::find(caloHitsToMerge.begin(), caloHitsToMerge.end(), pCaloHit) != caloHitsToMerge.end());
608  if (isAnExtrapolatedHit)
609  {
610  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::RemoveFromCluster(*this, pShowerCluster, pCaloHit));
611  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*this, pMainTrackCluster, pCaloHit));
612  }
613  else
614  {
615  const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
616  const bool isAbove(((connectingLineGradient * hitPosition.GetX()) + connectingLineIntercept) <
617  (isVertical ? hitPosition.GetX() : hitPosition.GetZ()));
618  const Cluster *&pClusterToModify(isAbove ? pAboveCluster : pBelowCluster);
619 
620  if (pClusterToModify)
621  {
622  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*this, pClusterToModify, pCaloHit));
623  }
624  else
625  {
627  parameters.m_caloHitList.push_back(pCaloHit);
628  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*this, parameters, pClusterToModify));
629 
630  remnantClusterList.push_back(pClusterToModify);
631  }
632  }
633  }
634  }
635 
636  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*this, fragmentListName, originalListName));
637 }
638 
639 //------------------------------------------------------------------------------------------------------------------------------------------
640 
641 void TrackRefinementBaseAlgorithm::ProcessRemnantClusters(const ClusterList &remnantClusterList, const Cluster *const pMainTrackCluster,
642  const ClusterList *const pClusterList, ClusterList &createdClusters) const
643 {
644  ClusterList fragmentedClusters;
645  for (const Cluster *const pRemnantCluster : remnantClusterList)
646  {
647  if (this->IsClusterRemnantDisconnected(pRemnantCluster))
648  {
649  this->FragmentRemnantCluster(pRemnantCluster, fragmentedClusters);
650  }
651  else
652  {
653  fragmentedClusters.push_back(pRemnantCluster);
654  }
655  }
656 
657  for (const Cluster *const pFragmentedCluster : fragmentedClusters)
658  {
659  if ((pFragmentedCluster->GetNCaloHits() == 1) && (this->AddToNearestCluster(pFragmentedCluster, pMainTrackCluster, pClusterList)))
660  continue;
661 
662  createdClusters.push_back(pFragmentedCluster);
663  }
664 }
665 
666 //------------------------------------------------------------------------------------------------------------------------------------------
667 
669  const Cluster *const pClusterToMerge, const Cluster *const pMainTrackCluster, const ClusterList *const pClusterList) const
670 {
671  const Cluster *pClosestCluster(nullptr);
672  float closestDistance(std::numeric_limits<float>::max());
673 
674  for (const Cluster *const pCluster : *pClusterList)
675  {
676  if (pCluster == pClusterToMerge)
677  continue;
678 
679  const float separationDistance(LArClusterHelper::GetClosestDistance(pClusterToMerge, pCluster));
680 
681  if (separationDistance < closestDistance)
682  {
683  if ((pCluster == pMainTrackCluster) && (separationDistance > m_maxDistanceFromMainTrack))
684  continue;
685 
686  pClosestCluster = pCluster;
687  closestDistance = separationDistance;
688  }
689  }
690 
691  if (closestDistance < m_maxHitDistanceFromCluster)
692  {
693  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*this, pClosestCluster, pClusterToMerge));
694  return true;
695  }
696 
697  return false;
698 }
699 
700 //------------------------------------------------------------------------------------------------------------------------------------------
701 
702 bool TrackRefinementBaseAlgorithm::IsClusterRemnantDisconnected(const Cluster *const pRemnantCluster) const
703 {
704  if (pRemnantCluster->GetNCaloHits() == 1)
705  return false;
706 
707  const OrderedCaloHitList &orderedCaloHitList(pRemnantCluster->GetOrderedCaloHitList());
708  const CaloHit *pPreviousCaloHit(orderedCaloHitList.begin()->second->front());
709 
710  for (const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
711  {
712  for (const CaloHit *const pCaloHit : *mapEntry.second)
713  {
714  if (pCaloHit == pPreviousCaloHit)
715  continue;
716 
717  const float separationDistanceSquared(pCaloHit->GetPositionVector().GetDistanceSquared(pPreviousCaloHit->GetPositionVector()));
718 
720  return true;
721 
722  pPreviousCaloHit = pCaloHit;
723  }
724  }
725 
726  return false;
727 }
728 
729 //------------------------------------------------------------------------------------------------------------------------------------------
730 
731 void TrackRefinementBaseAlgorithm::FragmentRemnantCluster(const Cluster *const pRemnantCluster, ClusterList &fragmentedClusterList) const
732 {
733  // Fragmentation initialisation
734  std::string originalListName, fragmentListName;
735  const ClusterList originalClusterList(1, pRemnantCluster);
736  PANDORA_THROW_RESULT_IF(
737  STATUS_CODE_SUCCESS, !=, PandoraContentApi::InitializeFragmentation(*this, originalClusterList, originalListName, fragmentListName));
738 
739  ClusterList createdClusters;
740 
741  const OrderedCaloHitList &orderedCaloHitList(pRemnantCluster->GetOrderedCaloHitList());
742  for (const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
743  {
744  for (const CaloHit *const pCaloHit : *mapEntry.second)
745  {
746  const Cluster *pClosestCluster(nullptr);
747 
748  if (!createdClusters.empty())
749  {
750  float closestDistance(std::numeric_limits<float>::max());
751 
752  for (const Cluster *const pCreatedCluster : createdClusters)
753  {
754  const float separationDistance(LArClusterHelper::GetClosestDistance(pCaloHit->GetPositionVector(), pCreatedCluster));
755  if ((separationDistance < closestDistance) && (separationDistance < m_maxHitDistanceFromCluster))
756  {
757  closestDistance = separationDistance;
758  pClosestCluster = pCreatedCluster;
759  }
760  }
761  }
762 
763  if (pClosestCluster)
764  {
765  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*this, pClosestCluster, pCaloHit));
766  }
767  else
768  {
770  parameters.m_caloHitList.push_back(pCaloHit);
771  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*this, parameters, pClosestCluster));
772  createdClusters.push_back(pClosestCluster);
773  }
774  }
775  }
776 
777  // End fragmentation
778  if (createdClusters.empty())
779  {
780  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*this, originalListName, fragmentListName));
781  fragmentedClusterList.push_back(pRemnantCluster);
782  }
783  else
784  {
785  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*this, fragmentListName, originalListName));
786  fragmentedClusterList.insert(fragmentedClusterList.begin(), createdClusters.begin(), createdClusters.end());
787  }
788 }
789 
790 //------------------------------------------------------------------------------------------------------------------------------------------
791 
792 template <typename T>
793 void TrackRefinementBaseAlgorithm::UpdateContainers(const ClusterList &clustersToAdd, const ClusterList &clustersToDelete,
794  const T sortFunction, ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
795 {
796  //ATTN: Very important to first delete pointers from containers
797  for (const Cluster *const pClusterToDelete : clustersToDelete)
798  this->RemoveClusterFromContainers(pClusterToDelete, clusterVector, slidingFitResultMapPair);
799 
800  this->InitialiseContainers(&clustersToAdd, sortFunction, clusterVector, slidingFitResultMapPair);
801 }
802 
803 //------------------------------------------------------------------------------------------------------------------------------------------
804 
806  const Cluster *const pClusterToRemove, ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
807 {
808  const TwoDSlidingFitResultMap::const_iterator microFitToDelete(slidingFitResultMapPair.first->find(pClusterToRemove));
809  if (microFitToDelete != slidingFitResultMapPair.first->end())
810  slidingFitResultMapPair.first->erase(microFitToDelete);
811 
812  const TwoDSlidingFitResultMap::const_iterator macroFitToDelete(slidingFitResultMapPair.second->find(pClusterToRemove));
813  if (macroFitToDelete != slidingFitResultMapPair.second->end())
814  slidingFitResultMapPair.second->erase(macroFitToDelete);
815 
816  const ClusterVector::const_iterator clusterToDelete(std::find(clusterVector.begin(), clusterVector.end(), pClusterToRemove));
817  if (clusterToDelete != clusterVector.end())
818  clusterVector.erase(clusterToDelete);
819 }
820 
821 //------------------------------------------------------------------------------------------------------------------------------------------
822 
823 StatusCode TrackRefinementBaseAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
824 {
825  PANDORA_RETURN_RESULT_IF_AND_IF(
826  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinClusterLength", m_minClusterLength));
827 
828  PANDORA_RETURN_RESULT_IF_AND_IF(
829  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MicroSlidingFitWindow", m_microSlidingFitWindow));
830 
831  PANDORA_RETURN_RESULT_IF_AND_IF(
832  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MacroSlidingFitWindow", m_macroSlidingFitWindow));
833 
834  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
835  XmlHelper::ReadValue(xmlHandle, "StableRegionClusterFraction", m_stableRegionClusterFraction));
836 
837  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
838  XmlHelper::ReadValue(xmlHandle, "MergePointMinCosAngleDeviation", m_mergePointMinCosAngleDeviation));
839 
840  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
841  XmlHelper::ReadValue(xmlHandle, "MinHitFractionForHitRemoval", m_minHitFractionForHitRemoval));
842 
843  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
844  XmlHelper::ReadValue(xmlHandle, "MaxDistanceFromMainTrack", m_maxDistanceFromMainTrack));
845 
846  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
847  XmlHelper::ReadValue(xmlHandle, "MaxHitDistanceFromCluster", m_maxHitDistanceFromCluster));
848 
849  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
850  XmlHelper::ReadValue(xmlHandle, "MaxHitSeparationForConnectedCluster", m_maxHitSeparationForConnectedCluster));
851 
852  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxTrackGaps", m_maxTrackGaps));
853 
854  PANDORA_RETURN_RESULT_IF_AND_IF(
855  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "LineSegmentLength", m_lineSegmentLength));
856 
857  if (m_lineSegmentLength < std::numeric_limits<float>::epsilon())
858  {
859  std::cout << "TrackInEMShowerAlgorithm: Line segment length must be positive and nonzero" << std::endl;
860  throw STATUS_CODE_INVALID_PARAMETER;
861  }
862 
863  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "HitWidthMode", m_hitWidthMode));
864 
865  return STATUS_CODE_SUCCESS;
866 }
867 
868 //------------------------------------------------------------------------------------------------------------------------------------------
869 //------------------------------------------------------------------------------------------------------------------------------------------
870 
871 bool TrackRefinementBaseAlgorithm::SortByDistanceAlongLine::operator()(const pandora::CaloHit *const pLhs, const pandora::CaloHit *const pRhs) const
872 {
873  const CartesianVector lhsHitPosition(
875 
876  const CartesianVector rhsHitPosition(
878 
879  const float lhsLongitudinal = m_lineDirection.GetDotProduct(lhsHitPosition - m_startPoint);
880  const float rhsLongitudinal = m_lineDirection.GetDotProduct(rhsHitPosition - m_startPoint);
881 
882  if (std::fabs(lhsLongitudinal - rhsLongitudinal) > std::numeric_limits<float>::epsilon())
883  {
884  // ATTN: Order from closest to furthest away
885  return (lhsLongitudinal < rhsLongitudinal);
886  }
887 
888  // ATTN: To deal with tiebreaks
889  return LArClusterHelper::SortHitsByPulseHeight(pLhs, pRhs);
890 }
891 
892 //------------------------------------------------------------------------------------------------------------------------------------------
893 
894 typedef bool (*SortFunction)(const Cluster *, const Cluster *);
895 
896 template void TrackRefinementBaseAlgorithm::UpdateContainers<SortFunction>(
897  const ClusterList &, const ClusterList &, const SortFunction, ClusterVector &, SlidingFitResultMapPair &) const;
898 template void TrackRefinementBaseAlgorithm::InitialiseContainers<SortFunction>(
899  const ClusterList *, const SortFunction, ClusterVector &, SlidingFitResultMapPair &) const;
900 
901 } // namespace lar_content
float DistanceInGap(const pandora::CartesianVector &upstreamPoint, const pandora::CartesianVector &downstreamPoint, const pandora::CartesianVector &connectingLine, pandora::DetectorGapList &consideredGaps) const
Calculate the track length between two points that lies in gaps.
unsigned int m_macroSlidingFitWindow
The sliding fit window used in the fits contained within the macroSlidingFitResultMap.
bool m_hitWidthMode
Whether to consider the width of hits.
ClusterAssociation class.
static bool SortHitsByPulseHeight(const pandora::CaloHit *const pLhs, const pandora::CaloHit *const pRhs)
Sort calo hits by their pulse height.
Header file for the lar hit width helper class.
bool IsCloseToLine(const pandora::CartesianVector &hitPosition, const pandora::CartesianVector &lineStart, const pandora::CartesianVector &lineDirection, const float distanceToLine) const
Check whether a hit is close to a line.
bool IsInLineSegment(const pandora::CartesianVector &lowerBoundary, const pandora::CartesianVector &upperBoundary, const pandora::CartesianVector &point) const
Whether a position falls within a specified segment of the cluster connecting line.
void AddHitsToMainTrack(const pandora::Cluster *const pMainTrackCluster, const pandora::Cluster *const pShowerTrackCluster, const pandora::CaloHitList &caloHitsToMerge, const ClusterAssociation &clusterAssociation, pandora::ClusterList &remnantClusterList) const
Remove the hits from a shower cluster that belong to the main track and add them into the main track ...
float m_minClusterLength
The minimum length of a considered cluster.
double closestDistance(const TVector3 &line0, const TVector3 &line1, const TVector3 &p)
std::pair< TwoDSlidingFitResultMap *, TwoDSlidingFitResultMap * > SlidingFitResultMapPair
unsigned int m_maxTrackGaps
The maximum number of graps allowed in the extrapolated hit vector.
static constexpr bool
const pandora::CartesianVector GetUpstreamMergePoint() const
Returns the upstream cluster merge point.
std::unordered_map< const pandora::Cluster *, pandora::CaloHitList > ClusterToCaloHitListMap
static pandora::CartesianVector GetClosestPointToLine2D(const pandora::CartesianVector &lineStart, const pandora::CartesianVector &lineDirection, const pandora::CaloHit *const pCaloHit)
Consider the hit width to find the closest position of a calo hit to a specified line.
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)=0
float m_minHitFractionForHitRemoval
The threshold fraction of hits to be removed from the cluster for hit removal to proceed.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
virtual bool AreExtrapolatedHitsNearBoundaries(const pandora::CaloHitVector &extrapolatedHitVector, ClusterAssociation &clusterAssociation) const =0
Check the separation of the extremal extrapolated hits with the expected endpoints or...
bool IsTrackContinuous(const ClusterAssociation &clusterAssociation, const pandora::CaloHitVector &extrapolatedCaloHitVector) const
Check whether the extrapolatedCaloHitVector contains a continuous line of hits between the cluster me...
bool GetClusterMergingCoordinates(const TwoDSlidingFitResult &clusterMicroFitResult, const TwoDSlidingFitResult &clusterMacroFitResult, const TwoDSlidingFitResult &associatedMacroFitResult, const bool isEndUpstream, pandora::CartesianVector &clusterMergePosition, pandora::CartesianVector &clusterMergeDirection) const
Get the merging coordinate and direction for an input cluster with respect to an associated cluster...
bool(* SortFunction)(const Cluster *, const Cluster *)
bool AddToNearestCluster(const pandora::Cluster *const pClusterToMerge, const pandora::Cluster *const pMainTrackCluster, const pandora::ClusterList *const pClusterList) const
Add a cluster to the nearest cluster satisfying separation distance thresholds.
Header file for the geometry helper class.
float m_maxHitDistanceFromCluster
The threshold separation between a hit and cluster for the hit to be merged into the cluster...
bool AreExtrapolatedHitsGood(const ClusterToCaloHitListMap &clusterToCaloHitListMap, ClusterAssociation &clusterAssociation) const
Perform topological checks on the collected hits to ensure no gaps are present.
int GetMaxLayer() const
Get the maximum occupied layer in the sliding fit.
bool IsClusterRemnantDisconnected(const pandora::Cluster *const pRemnantCluster) const
Whether a remnant cluster is considered to be disconnected and therefore should undergo further fragm...
int GetMinLayer() const
Get the minimum occupied layer in the sliding fit.
void UpdateContainers(const pandora::ClusterList &clustersToAdd, const pandora::ClusterList &clustersToDelete, const T sortFunction, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
Remove deleted clusters from the cluster vector and sliding fit maps and add in created clusters that...
void FragmentRemnantCluster(const pandora::Cluster *const pRemnantCluster, pandora::ClusterList &fragmentedClusterList) const
Fragment a cluster using simple hit separation logic.
Header file for the cluster helper class.
pandora::StatusCode GetGlobalFitPosition(const float rL, pandora::CartesianVector &position) const
Get global fit position for a given longitudinal coordinate.
float m_maxHitSeparationForConnectedCluster
The maximum separation between two adjacent (in z) hits in a connected cluster.
void ProcessRemnantClusters(const pandora::ClusterList &remnantClusterList, const pandora::Cluster *const pMainTrackCluster, const pandora::ClusterList *const pClusterList, pandora::ClusterList &createdClusters) const
Process the remnant clusters separating those that stradle the main track.
float m_stableRegionClusterFraction
The threshold fraction of fit contributing layers which defines the stable region.
std::map< int, LayerFitResult > LayerFitResultMap
void RepositionIfInGap(const pandora::CartesianVector &mergeDirection, pandora::CartesianVector &trackPoint) const
Move an input position to the higher line gap edge if it lies within a gap.
float m_lineSegmentLength
The length of a track gap.
const pandora::CartesianVector GetDownstreamMergePoint() const
Returns the downstream cluster merge point.
void GetGlobalDirection(const float dTdL, pandora::CartesianVector &direction) const
Get global direction coordinates for given sliding linear fit gradient.
const LayerFitResultMap & GetLayerFitResultMap() const
Get the layer fit result map.
std::unordered_map< const pandora::Cluster *, TwoDSlidingFitResult > TwoDSlidingFitResultMap
fhicl::Table< sbnd::crt::CRTDetSimParams > Parameters
static float GetClosestDistanceToPoint2D(const pandora::CaloHit *const pCaloHit, const pandora::CartesianVector &point2D)
Consider the hit width to find the smallest distance between a calo hit and a given point...
void InitialiseContainers(const pandora::ClusterList *pClusterList, const T sortFunction, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
Fill the cluster vector and sliding fit maps with clusters that are determined to be track-like...
void RemoveClusterFromContainers(const pandora::Cluster *const pClustertoRemove, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
Remove a cluster from the cluster vector and sliding fit maps.
Header file for the track refinement base class.
required by fuzzyCluster table::sbnd_g4_services gaushitTruthMatch pandora
Definition: reco_sbnd.fcl:182
bool IsInBoundingBox(const float minX, const float maxX, const float minZ, const float maxZ, const pandora::CartesianVector &hitPosition) const
check whether a hit is contained within a defined square region
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
float m_maxDistanceFromMainTrack
The threshold distance for a hit to be added to the main track.
bool operator()(const pandora::CaloHit *const pLhs, const pandora::CaloHit *const pRhs) const
Sort hits by their projected distance along a line from a start point.
void GetHitsInBoundingBox(const pandora::CartesianVector &firstCorner, const pandora::CartesianVector &secondCorner, const pandora::ClusterList *const pClusterList, ClusterToCaloHitListMap &clusterToCaloHitListMap, const pandora::ClusterList &unavailableProtectedClusters=pandora::ClusterList(), const float distanceToLine=-1.f) const
Find the unprotected hits that are contained within a defined box with the option to apply a cut on t...
std::vector< art::Ptr< recob::Cluster > > ClusterVector
bool IsNearBoundary(const pandora::CaloHit *const pCaloHit, const pandora::CartesianVector &boundaryPosition2D, const float boundaryTolerance) const
Check whether a hit is close to a boundary point.
const pandora::Cluster * RemoveOffAxisHitsFromTrack(const pandora::Cluster *const pCluster, const pandora::CartesianVector &splitPosition, const bool isEndUpstream, const ClusterToCaloHitListMap &clusterToCaloHitListMap, pandora::ClusterList &remnantClusterList, TwoDSlidingFitResultMap &microSlidingFitResultMap, TwoDSlidingFitResultMap &macroSlidingFitResultMap) const
Remove any hits in the upstream/downstream cluster that lie off of the main track axis (i...
void GetTrackSegmentBoundaries(const ClusterAssociation &clusterAssociation, pandora::CartesianPointVector &trackSegmentBoundaries) const
Obtain the segment boundaries of the connecting line to test whether extrapolated hits are continuous...
const pandora::CartesianVector GetConnectingLineDirection() const
Returns the unit vector of the line connecting the upstream and downstream merge points (upstream -&gt; ...
void GetLocalPosition(const pandora::CartesianVector &position, float &rL, float &rT) const
Get local sliding fit coordinates for a given global position.
unsigned int m_microSlidingFitWindow
The sliding fit window used in the fits contained within the microSlidingFitResultMap.
BEGIN_PROLOG could also be cout
float m_mergePointMinCosAngleDeviation
The threshold cos opening angle between the cluster local gradient and the associated cluster global ...
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.