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