LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
TracksCrossingGapsTool.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
13 
16 
17 using namespace pandora;
18 
19 namespace lar_content
20 {
21 
22 TracksCrossingGapsTool::TracksCrossingGapsTool() :
23  m_minMatchedFraction(0.5f),
24  m_minMatchedSamplingPoints(10),
25  m_minXOverlapFraction(0.9f),
26  m_minMatchedSamplingPointRatio(2),
27  m_maxGapTolerance(2.f),
28  m_sampleStepSize(0.5f),
29  m_maxAngleRatio(2)
30 {
31 }
32 
33 //------------------------------------------------------------------------------------------------------------------------------------------
34 
36 {
37  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
38  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
39 
40  if (PandoraContentApi::GetGeometry(*pAlgorithm)->GetDetectorGapList().empty())
41  return false;
42 
43  ProtoParticleVector protoParticleVector;
44  this->FindTracks(pAlgorithm, overlapTensor, protoParticleVector);
45 
46  const bool particlesMade(pAlgorithm->CreateThreeDParticles(protoParticleVector));
47  return particlesMade;
48 }
49 
50 //------------------------------------------------------------------------------------------------------------------------------------------
51 
53  ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const TensorType &overlapTensor, ProtoParticleVector &protoParticleVector) const
54 {
55  ClusterSet usedClusters;
56  ClusterVector sortedKeyClusters;
57  overlapTensor.GetSortedKeyClusters(sortedKeyClusters);
58 
59  for (const Cluster *const pKeyCluster : sortedKeyClusters)
60  {
61  if (!pKeyCluster->IsAvailable())
62  continue;
63 
64  unsigned int nU(0), nV(0), nW(0);
65  TensorType::ElementList elementList;
66  overlapTensor.GetConnectedElements(pKeyCluster, true, elementList, nU, nV, nW);
67 
68  IteratorList iteratorList;
69  this->SelectElements(pAlgorithm, elementList, usedClusters, iteratorList);
70 
71  // Check that elements are not directly connected and are significantly longer than any other directly connected elements
72  for (IteratorList::const_iterator iIter = iteratorList.begin(), iIterEnd = iteratorList.end(); iIter != iIterEnd; ++iIter)
73  {
74  if (LongTracksTool::HasLongDirectConnections(iIter, iteratorList))
75  continue;
76 
78  continue;
79 
80  ProtoParticle protoParticle;
81  protoParticle.m_clusterList.push_back((*iIter)->GetClusterU());
82  protoParticle.m_clusterList.push_back((*iIter)->GetClusterV());
83  protoParticle.m_clusterList.push_back((*iIter)->GetClusterW());
84  protoParticleVector.push_back(protoParticle);
85 
86  usedClusters.insert((*iIter)->GetClusterU());
87  usedClusters.insert((*iIter)->GetClusterV());
88  usedClusters.insert((*iIter)->GetClusterW());
89  }
90  }
91 }
92 
93 //------------------------------------------------------------------------------------------------------------------------------------------
94 
96  const TensorType::ElementList &elementList, const pandora::ClusterSet &usedClusters, IteratorList &iteratorList) const
97 {
98  for (TensorType::ElementList::const_iterator eIter = elementList.begin(); eIter != elementList.end(); ++eIter)
99  {
100  if (usedClusters.count(eIter->GetClusterU()) || usedClusters.count(eIter->GetClusterV()) || usedClusters.count(eIter->GetClusterW()))
101  continue;
102 
103  if (eIter->GetOverlapResult().GetMatchedFraction() < m_minMatchedFraction)
104  continue;
105 
106  if (eIter->GetOverlapResult().GetNMatchedSamplingPoints() < m_minMatchedSamplingPoints)
107  continue;
108 
109  const XOverlap &xOverlap(eIter->GetOverlapResult().GetXOverlap());
110 
111  if (xOverlap.GetXOverlapSpan() < std::numeric_limits<float>::epsilon())
112  continue;
113 
114  // Calculate effective overlap fraction, including the information about gaps
115  float xOverlapFractionU(0.f), xOverlapFractionV(0.f), xOverlapFractionW(0.f);
116  this->CalculateEffectiveOverlapFractions(pAlgorithm, *eIter, xOverlapFractionU, xOverlapFractionV, xOverlapFractionW);
117 
118  if ((xOverlap.GetXSpanU() > std::numeric_limits<float>::epsilon()) && (xOverlapFractionU > m_minXOverlapFraction) &&
119  (xOverlap.GetXSpanV() > std::numeric_limits<float>::epsilon()) && (xOverlapFractionV > m_minXOverlapFraction) &&
120  (xOverlap.GetXSpanW() > std::numeric_limits<float>::epsilon()) && (xOverlapFractionW > m_minXOverlapFraction))
121  {
122  iteratorList.push_back(eIter);
123  }
124  }
125 }
126 
127 //------------------------------------------------------------------------------------------------------------------------------------------
128 
130  const TensorType::Element &element, float &xOverlapFractionU, float &xOverlapFractionV, float &xOverlapFractionW) const
131 {
132  float xMinEffU(element.GetOverlapResult().GetXOverlap().GetUMinX()), xMaxEffU(element.GetOverlapResult().GetXOverlap().GetUMaxX());
133  float xMinEffV(element.GetOverlapResult().GetXOverlap().GetVMinX()), xMaxEffV(element.GetOverlapResult().GetXOverlap().GetVMaxX());
134  float xMinEffW(element.GetOverlapResult().GetXOverlap().GetWMinX()), xMaxEffW(element.GetOverlapResult().GetXOverlap().GetWMaxX());
135  this->CalculateEffectiveOverlapSpan(pAlgorithm, element, xMinEffU, xMaxEffU, xMinEffV, xMaxEffV, xMinEffW, xMaxEffW);
136 
137  const float effectiveXSpanU(xMaxEffU - xMinEffU), effectiveXSpanV(xMaxEffV - xMinEffV), effectiveXSpanW(xMaxEffW - xMinEffW);
138  const float minCommonX(std::max(xMinEffU, std::max(xMinEffV, xMinEffW)));
139  const float maxCommonX(std::min(xMaxEffU, std::min(xMaxEffV, xMaxEffW)));
140  const float effectiveXOverlapSpan(maxCommonX - minCommonX);
141 
142  // TODO check that this shouldn't be greater than 1 any more
143  xOverlapFractionU = effectiveXSpanU > 0.f ? std::min(1.f, (effectiveXOverlapSpan / effectiveXSpanU)) : 0.f;
144  xOverlapFractionV = effectiveXSpanV > 0.f ? std::min(1.f, (effectiveXOverlapSpan / effectiveXSpanV)) : 0.f;
145  xOverlapFractionW = effectiveXSpanW > 0.f ? std::min(1.f, (effectiveXOverlapSpan / effectiveXSpanW)) : 0.f;
146 }
147 
148 //------------------------------------------------------------------------------------------------------------------------------------------
149 
151  const TensorType::Element &element, float &xMinEffU, float &xMaxEffU, float &xMinEffV, float &xMaxEffV, float &xMinEffW, float &xMaxEffW) const
152 {
153  const float xMinAll(std::min(xMinEffU, std::min(xMinEffV, xMinEffW)));
154  const float xMaxAll(std::max(xMaxEffU, std::max(xMaxEffV, xMaxEffW)));
155  const float minCommonX(std::max(xMinEffU, std::max(xMinEffV, xMinEffW)));
156  const float maxCommonX(std::min(xMaxEffU, std::min(xMaxEffV, xMaxEffW)));
157 
158  float dxUmin(0.f), dxVmin(0.f), dxWmin(0.f);
159  float dxUmax(0.f), dxVmax(0.f), dxWmax(0.f);
160 
161  // ATTN break out of loops to to avoid finding a non-related gap far from cluster itself
162  const int nSamplingPointsLeft(1 + static_cast<int>((minCommonX - xMinAll) / m_sampleStepSize));
163  const int nSamplingPointsRight(1 + static_cast<int>((xMaxAll - maxCommonX) / m_sampleStepSize));
164 
165  for (int iSample = 1; iSample <= nSamplingPointsLeft; ++iSample)
166  {
167  bool gapInU(false), gapInV(false), gapInW(false);
168  const float xSample(std::max(xMinAll, minCommonX - static_cast<float>(iSample) * m_sampleStepSize));
169 
170  if (!this->PassesGapChecks(pAlgorithm, element, xSample, gapInU, gapInV, gapInW))
171  break;
172 
173  if (gapInU)
174  dxUmin = xMinEffU - xSample;
175  if (gapInV)
176  dxVmin = xMinEffV - xSample;
177  if (gapInW)
178  dxWmin = xMinEffW - xSample;
179  }
180 
181  for (int iSample = 1; iSample <= nSamplingPointsRight; ++iSample)
182  {
183  bool gapInU(false), gapInV(false), gapInW(false);
184  const float xSample(std::min(xMaxAll, maxCommonX + static_cast<float>(iSample) * m_sampleStepSize));
185 
186  if (!this->PassesGapChecks(pAlgorithm, element, xSample, gapInU, gapInV, gapInW))
187  break;
188 
189  if (gapInU)
190  dxUmax = xSample - xMaxEffU;
191  if (gapInV)
192  dxVmax = xSample - xMaxEffV;
193  if (gapInW)
194  dxWmax = xSample - xMaxEffW;
195  }
196 
197  xMinEffU -= dxUmin;
198  xMaxEffU += dxUmax;
199  xMinEffV -= dxVmin;
200  xMaxEffV += dxVmax;
201  xMinEffW -= dxWmin;
202  xMaxEffW += dxWmax;
203 }
204 
205 //------------------------------------------------------------------------------------------------------------------------------------------
206 
207 bool TracksCrossingGapsTool::PassesGapChecks(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const TensorType::Element &element,
208  const float xSample, bool &gapInU, bool &gapInV, bool &gapInW) const
209 {
210  const TwoDSlidingFitResult &slidingFitResultU(pAlgorithm->GetCachedSlidingFitResult(element.GetClusterU()));
211  const TwoDSlidingFitResult &slidingFitResultV(pAlgorithm->GetCachedSlidingFitResult(element.GetClusterV()));
212  const TwoDSlidingFitResult &slidingFitResultW(pAlgorithm->GetCachedSlidingFitResult(element.GetClusterW()));
213 
214  // If we have access to the global x position in all three clusters, there are no gaps involved (or cluster already spans small gaps)
215  CartesianVector fitUPosition(0.f, 0.f, 0.f), fitVPosition(0.f, 0.f, 0.f), fitWPosition(0.f, 0.f, 0.f);
216  const StatusCode statusCodeU(slidingFitResultU.GetGlobalFitPositionAtX(xSample, fitUPosition));
217  const StatusCode statusCodeV(slidingFitResultV.GetGlobalFitPositionAtX(xSample, fitVPosition));
218  const StatusCode statusCodeW(slidingFitResultW.GetGlobalFitPositionAtX(xSample, fitWPosition));
219 
220  if ((STATUS_CODE_SUCCESS == statusCodeU) && (STATUS_CODE_SUCCESS == statusCodeV) && (STATUS_CODE_SUCCESS == statusCodeW))
221  return false;
222 
223  try
224  {
225  // Note: argument order important - initially assume first view has a gap, but inside CheckXPositionInGap do check other two views
226  if ((STATUS_CODE_SUCCESS != statusCodeU) && (!this->IsEndOfCluster(xSample, slidingFitResultU)))
227  return this->CheckXPositionInGap(xSample, slidingFitResultU, slidingFitResultV, slidingFitResultW, gapInU, gapInV, gapInW);
228 
229  if ((STATUS_CODE_SUCCESS != statusCodeV) && (!this->IsEndOfCluster(xSample, slidingFitResultV)))
230  return this->CheckXPositionInGap(xSample, slidingFitResultV, slidingFitResultU, slidingFitResultW, gapInV, gapInU, gapInW);
231 
232  if ((STATUS_CODE_SUCCESS != statusCodeW) && (!this->IsEndOfCluster(xSample, slidingFitResultW)))
233  return this->CheckXPositionInGap(xSample, slidingFitResultW, slidingFitResultU, slidingFitResultV, gapInW, gapInU, gapInV);
234  }
235  catch (const StatusCodeException &statusCodeException)
236  {
237  }
238 
239  return false;
240 }
241 
242 //------------------------------------------------------------------------------------------------------------------------------------------
243 
244 bool TracksCrossingGapsTool::CheckXPositionInGap(const float xSample, const TwoDSlidingFitResult &slidingFitResult1,
245  const TwoDSlidingFitResult &slidingFitResult2, const TwoDSlidingFitResult &slidingFitResult3, bool &gapIn1, bool &gapIn2, bool &gapIn3) const
246 {
247  CartesianVector fitPosition2(0.f, 0.f, 0.f), fitPosition3(0.f, 0.f, 0.f);
248 
249  // If we have the global position at X from the two other clusters, calculate projection in the first view and check for gaps
250  if ((STATUS_CODE_SUCCESS == slidingFitResult2.GetGlobalFitPositionAtX(xSample, fitPosition2)) &&
251  (STATUS_CODE_SUCCESS == slidingFitResult3.GetGlobalFitPositionAtX(xSample, fitPosition3)))
252  {
253  const HitType hitType1(LArClusterHelper::GetClusterHitType(slidingFitResult1.GetCluster()));
254  const HitType hitType2(LArClusterHelper::GetClusterHitType(slidingFitResult2.GetCluster()));
255  const HitType hitType3(LArClusterHelper::GetClusterHitType(slidingFitResult3.GetCluster()));
256 
257  const float zSample(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType2, hitType3, fitPosition2.GetZ(), fitPosition3.GetZ()));
258  const CartesianVector samplingPoint(xSample, 0.f, zSample);
259  return LArGeometryHelper::IsInGap(this->GetPandora(), CartesianVector(xSample, 0.f, zSample), hitType1, m_maxGapTolerance);
260  }
261 
262  // ATTN Only safe to return here (for efficiency) because gapIn2 and gapIn3 values aren't used by calling function if we return false
263  gapIn1 = LArGeometryHelper::IsXSamplingPointInGap(this->GetPandora(), xSample, slidingFitResult1, m_sampleStepSize);
264 
265  if (!gapIn1)
266  return false;
267 
268  // If we dont have a projection at x in the other two clusters, check if they are in gaps or at the end of the cluster
269  if ((STATUS_CODE_SUCCESS != slidingFitResult2.GetGlobalFitPositionAtX(xSample, fitPosition2)) &&
270  (STATUS_CODE_SUCCESS != slidingFitResult3.GetGlobalFitPositionAtX(xSample, fitPosition3)))
271  {
272  const bool endIn2(this->IsEndOfCluster(xSample, slidingFitResult2));
273  const bool endIn3(this->IsEndOfCluster(xSample, slidingFitResult3));
274 
275  if (!endIn2)
276  gapIn2 = LArGeometryHelper::IsXSamplingPointInGap(this->GetPandora(), xSample, slidingFitResult2, m_sampleStepSize);
277 
278  if (!endIn3)
279  gapIn3 = LArGeometryHelper::IsXSamplingPointInGap(this->GetPandora(), xSample, slidingFitResult3, m_sampleStepSize);
280 
281  return ((gapIn2 && endIn3) || (gapIn3 && endIn2) || (endIn2 && endIn3));
282  }
283 
284  // Finally, check whether there is a second gap involved
285  if (STATUS_CODE_SUCCESS != slidingFitResult2.GetGlobalFitPositionAtX(xSample, fitPosition2))
286  {
287  gapIn2 = LArGeometryHelper::IsXSamplingPointInGap(this->GetPandora(), xSample, slidingFitResult2, m_sampleStepSize);
288  return (gapIn2 || this->IsEndOfCluster(xSample, slidingFitResult2));
289  }
290  else
291  {
292  gapIn3 = LArGeometryHelper::IsXSamplingPointInGap(this->GetPandora(), xSample, slidingFitResult3, m_sampleStepSize);
293  return (gapIn3 || this->IsEndOfCluster(xSample, slidingFitResult3));
294  }
295 }
296 
297 //------------------------------------------------------------------------------------------------------------------------------------------
298 
299 bool TracksCrossingGapsTool::IsEndOfCluster(const float xSample, const TwoDSlidingFitResult &slidingFitResult) const
300 {
301  return ((std::fabs(slidingFitResult.GetGlobalMinLayerPosition().GetX() - xSample) < slidingFitResult.GetLayerPitch()) ||
302  (std::fabs(slidingFitResult.GetGlobalMaxLayerPosition().GetX() - xSample) < slidingFitResult.GetLayerPitch()));
303 }
304 
305 //------------------------------------------------------------------------------------------------------------------------------------------
306 
307 StatusCode TracksCrossingGapsTool::ReadSettings(const TiXmlHandle xmlHandle)
308 {
309  PANDORA_RETURN_RESULT_IF_AND_IF(
310  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinMatchedFraction", m_minMatchedFraction));
311 
312  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
313  XmlHelper::ReadValue(xmlHandle, "MinMatchedSamplingPoints", m_minMatchedSamplingPoints));
314 
315  PANDORA_RETURN_RESULT_IF_AND_IF(
316  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinXOverlapFraction", m_minXOverlapFraction));
317 
318  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
319  XmlHelper::ReadValue(xmlHandle, "MinMatchedSamplingPointRatio", m_minMatchedSamplingPointRatio));
320 
321  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxGapTolerance", m_maxGapTolerance));
322 
323  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SampleStepSize", m_sampleStepSize));
324 
325  if (m_sampleStepSize < std::numeric_limits<float>::epsilon())
326  {
327  std::cout << "TracksCrossingGapsTool: Invalid value for SampleStepSize " << m_sampleStepSize << std::endl;
328  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
329  }
330 
331  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxAngleRatio", m_maxAngleRatio));
332 
333  return STATUS_CODE_SUCCESS;
334 }
335 
336 } // namespace lar_content
unsigned int m_minMatchedSamplingPoints
The min number of matched sampling points for particle creation.
std::vector< ProtoParticle > ProtoParticleVector
void CalculateEffectiveOverlapSpan(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const TensorType::Element &element, float &xMinEffU, float &xMaxEffU, float &xMinEffV, float &xMaxEffV, float &xMinEffW, float &xMaxEffW) const
Calculate the effective overlap span given a set of clusters, taking gaps into account.
void CalculateEffectiveOverlapFractions(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const TensorType::Element &element, float &xOverlapFractionU, float &xOverlapFractionV, float &xOverlapFractionW) const
Calculate the effective overlap fractions given a set of clusters, taking gaps into account...
float m_maxGapTolerance
The max gap tolerance.
std::vector< TensorType::ElementList::const_iterator > IteratorList
static bool IsLongerThanDirectConnections(IteratorList::const_iterator iIter, const TensorType::ElementList &elementList, const unsigned int minMatchedSamplingPointRatio, const pandora::ClusterSet &usedClusters)
Whether a long element is significantly longer that other elements with which it shares a cluster...
const TwoDSlidingFitResult & GetCachedSlidingFitResult(const pandora::Cluster *const pCluster) const
Get a sliding fit result from the algorithm cache.
float m_minXOverlapFraction
The min x overlap fraction (in each view) for particle creation.
void GetConnectedElements(const pandora::Cluster *const pCluster, const bool ignoreUnavailable, ElementList &elementList) const
Get a list of elements connected to a specified cluster.
void FindTracks(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const TensorType &overlapTensor, ProtoParticleVector &protoParticleVector) const
Find tracks crossing gaps, with unambiguous connection but poor overlap due to gaps.
intermediate_table::const_iterator const_iterator
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
static bool IsInGap(const pandora::Pandora &pandora, const pandora::CartesianVector &testPoint2D, const pandora::HitType hitType, const float gapTolerance=0.f)
Whether a 2D test point lies in a registered gap with the associated hit type.
void SelectElements(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const TensorType::ElementList &elementList, const pandora::ClusterSet &usedClusters, IteratorList &iteratorList) const
Select a list of track-like elements crossing a gap in one or more views from a set of connected tens...
TFile f
Definition: plotHisto.C:6
Header file for the geometry helper class.
unsigned int m_minMatchedSamplingPointRatio
The min ratio between 1st and 2nd highest msps for simple ambiguity resolution.
bool CheckXPositionInGap(const float xSample, const TwoDSlidingFitResult &slidingFitResult1, const TwoDSlidingFitResult &slidingFitResult2, const TwoDSlidingFitResult &slidingFitResult3, bool &gapIn1, bool &gapIn2, bool &gapIn3) const
Check individually each cluster where a gap might be present.
bool IsEndOfCluster(const float xSample, const TwoDSlidingFitResult &slidingFitResult) const
Check whether a x position is at the end of the cluster.
Header file for the cluster helper class.
float m_minMatchedFraction
The min matched sampling point fraction for particle creation.
bool Run(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, TensorType &overlapTensor)
Run the algorithm tool.
pandora::ClusterList m_clusterList
List of 2D clusters in a 3D proto particle.
static float MergeTwoPositions(const pandora::Pandora &pandora, const pandora::HitType view1, const pandora::HitType view2, const float position1, const float position2)
Merge two views (U,V) to give a third view (Z).
float GetLayerPitch() const
Get the layer pitch, units cm.
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
Header file for the long tracks tool class.
void GetSortedKeyClusters(pandora::ClusterVector &sortedKeyClusters) const
Get a sorted vector of key clusters (U clusters with current implementation)
bool PassesGapChecks(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const TensorType::Element &element, const float xSample, bool &gapInU, bool &gapInV, bool &gapInW) const
Check whether there is any gap in the three U-V-W clusters combination.
static bool IsXSamplingPointInGap(const pandora::Pandora &pandora, const float xSample, const TwoDSlidingFitResult &slidingFitResult, const float gapTolerance=0.f)
Whether there is a gap in a cluster (described via its sliding fit result) at a specified x sampling ...
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
unsigned int m_maxAngleRatio
The max ratio allowed in the angle.
pandora::StatusCode GetGlobalFitPositionAtX(const float x, pandora::CartesianVector &position) const
Get global fit position for a given input x coordinate.
HitType
Definition: HitType.h:12
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
virtual bool CreateThreeDParticles(const ProtoParticleVector &protoParticleVector)
Create particles using findings from recent algorithm processing.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
static bool HasLongDirectConnections(IteratorList::const_iterator iIter, const IteratorList &iteratorList)
Whether a long element shares clusters with any other long elements.
float m_sampleStepSize
The sampling step size used in association checks, units cm.
XOverlap class.
Definition: LArXOverlap.h:17
pandora::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
Header file for the long tracks tool class.