LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
EventSlicingTool.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
15 
18 
20 
22 
23 using namespace pandora;
24 
25 namespace lar_content
26 {
27 
28 //------------------------------------------------------------------------------------------------------------------------------------------
29 
30 EventSlicingTool::EventSlicingTool() :
31  m_minHitsPer3DCluster(20),
32  m_min3DHitsToSeedNewSlice(50),
33  m_halfWindowLayers(20),
34  m_usePointingAssociation(true),
35  m_minVertexLongitudinalDistance(-7.5f),
36  m_maxVertexLongitudinalDistance(60.f),
37  m_maxVertexTransverseDistance(10.5f),
38  m_vertexAngularAllowance(9.f),
39  m_maxClosestApproach(15.f),
40  m_maxInterceptDistance(60.f),
41  m_useProximityAssociation(true),
42  m_maxHitSeparationSquared(25.f * 25.f),
43  m_useShowerConeAssociation(true),
44  m_nConeFitLayers(20),
45  m_nConeFits(5),
46  m_coneLengthMultiplier(7.f),
47  m_maxConeLength(126.f),
48  m_coneTanHalfAngle1(0.5f),
49  m_coneBoundedFraction1(0.5f),
50  m_coneTanHalfAngle2(0.75f),
51  m_coneBoundedFraction2(0.75f),
52  m_use3DProjectionsInHitPickUp(true)
53 {
54 }
55 
56 //------------------------------------------------------------------------------------------------------------------------------------------
57 
58 void EventSlicingTool::RunSlicing(const Algorithm *const pAlgorithm, const HitTypeToNameMap &caloHitListNames,
59  const HitTypeToNameMap &clusterListNames, SliceList &sliceList)
60 {
61  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
62  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
63 
64  ClusterToPfoMap clusterToPfoMap;
65 
66  ClusterList trackClusters3D;
67  this->GetThreeDClusters(pAlgorithm, m_trackPfoListName, trackClusters3D, clusterToPfoMap);
68 
69  ClusterList showerClusters3D;
70  this->GetThreeDClusters(pAlgorithm, m_showerPfoListName, showerClusters3D, clusterToPfoMap);
71 
72  ClusterSliceList clusterSliceList;
73  this->GetClusterSliceList(trackClusters3D, showerClusters3D, clusterSliceList);
74 
75  if (clusterSliceList.size() < 2)
76  {
77  return this->CopyAllHitsToSingleSlice(pAlgorithm, caloHitListNames, sliceList);
78  }
79  else
80  {
81  ClusterToSliceIndexMap clusterToSliceIndexMap;
82  this->CreateSlices(clusterSliceList, sliceList, clusterToSliceIndexMap);
83 
84  ClusterSet assignedClusters;
85  this->CopyPfoHitsToSlices(clusterToSliceIndexMap, clusterToPfoMap, sliceList, assignedClusters);
86 
87  ClusterList remainingClusters;
88  this->GetRemainingClusters(pAlgorithm, clusterListNames, assignedClusters, remainingClusters);
89 
90  this->AssignRemainingHitsToSlices(remainingClusters, clusterToSliceIndexMap, sliceList);
91  }
92 }
93 
94 //------------------------------------------------------------------------------------------------------------------------------------------
95 
96 void EventSlicingTool::CopyAllHitsToSingleSlice(const Algorithm *const pAlgorithm, const HitTypeToNameMap &caloHitListNames, SliceList &sliceList) const
97 {
98  if (!sliceList.empty())
99  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
100 
101  const CaloHitList *pCaloHitListU(nullptr);
102  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=,
103  PandoraContentApi::GetList(*pAlgorithm, caloHitListNames.at(TPC_VIEW_U), pCaloHitListU));
104 
105  const CaloHitList *pCaloHitListV(nullptr);
106  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=,
107  PandoraContentApi::GetList(*pAlgorithm, caloHitListNames.at(TPC_VIEW_V), pCaloHitListV));
108 
109  const CaloHitList *pCaloHitListW(nullptr);
110  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=,
111  PandoraContentApi::GetList(*pAlgorithm, caloHitListNames.at(TPC_VIEW_W), pCaloHitListW));
112 
113  if (pCaloHitListU || pCaloHitListV || pCaloHitListW)
114  {
115  sliceList.push_back(Slice());
116  Slice &slice(sliceList.at(0));
117 
118  if (pCaloHitListU)
119  slice.m_caloHitListU = *pCaloHitListU;
120  if (pCaloHitListV)
121  slice.m_caloHitListV = *pCaloHitListV;
122  if (pCaloHitListW)
123  slice.m_caloHitListW = *pCaloHitListW;
124  }
125 }
126 
127 //------------------------------------------------------------------------------------------------------------------------------------------
128 
130  const Algorithm *const pAlgorithm, const std::string &pfoListName, ClusterList &clusters3D, ClusterToPfoMap &clusterToPfoMap) const
131 {
132  const PfoList *pPfoList(nullptr);
133  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*pAlgorithm, pfoListName, pPfoList));
134 
135  if (!pPfoList || pPfoList->empty())
136  {
137  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
138  std::cout << "EventSlicingTool: unable to find pfo list " << pfoListName << std::endl;
139 
140  return;
141  }
142 
143  for (const ParticleFlowObject *const pPfo : *pPfoList)
144  {
145  ClusterList pfoClusters3D;
146  LArPfoHelper::GetThreeDClusterList(pPfo, pfoClusters3D);
147 
148  for (const Cluster *const pCluster3D : pfoClusters3D)
149  {
150  if (pCluster3D->GetNCaloHits() < m_minHitsPer3DCluster)
151  continue;
152 
153  if (!clusterToPfoMap.insert(ClusterToPfoMap::value_type(pCluster3D, pPfo)).second)
154  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
155 
156  if (clusters3D.end() != std::find(clusters3D.begin(), clusters3D.end(), pCluster3D))
157  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
158 
159  clusters3D.push_back(pCluster3D);
160  }
161  }
162 }
163 
164 //------------------------------------------------------------------------------------------------------------------------------------------
165 
166 void EventSlicingTool::GetClusterSliceList(const ClusterList &trackClusters3D, const ClusterList &showerClusters3D, ClusterSliceList &clusterSliceList) const
167 {
168  const float pitchU{LArGeometryHelper::GetWirePitch(this->GetPandora(), TPC_VIEW_U)};
169  const float pitchV{LArGeometryHelper::GetWirePitch(this->GetPandora(), TPC_VIEW_V)};
170  const float pitchW{LArGeometryHelper::GetWirePitch(this->GetPandora(), TPC_VIEW_W)};
171  const float pitchMax{std::max({pitchU, pitchV, pitchW})};
172  const float layerPitch(pitchMax);
173 
174  ThreeDSlidingFitResultMap trackFitResults;
175 
176  for (const Cluster *const pCluster3D : trackClusters3D)
177  {
178  try
179  {
180  trackFitResults.insert(
181  ThreeDSlidingFitResultMap::value_type(pCluster3D, ThreeDSlidingFitResult(pCluster3D, m_halfWindowLayers, layerPitch)));
182  }
183  catch (StatusCodeException &)
184  {
185  std::cout << "EventSlicingTool: ThreeDSlidingFitResult failure for track cluster." << std::endl;
186  }
187  }
188 
189  ThreeDSlidingConeFitResultMap showerConeFitResults;
190 
191  for (const Cluster *const pCluster3D : showerClusters3D)
192  {
193  try
194  {
195  showerConeFitResults.insert(
196  ThreeDSlidingConeFitResultMap::value_type(pCluster3D, ThreeDSlidingConeFitResult(pCluster3D, m_halfWindowLayers, layerPitch)));
197  }
198  catch (StatusCodeException &)
199  {
200  std::cout << "EventSlicingTool: ThreeDSlidingConeFitResult failure for shower cluster." << std::endl;
201  }
202  }
203 
204  ClusterVector sortedClusters3D(trackClusters3D.begin(), trackClusters3D.end());
205  sortedClusters3D.insert(sortedClusters3D.end(), showerClusters3D.begin(), showerClusters3D.end());
206  std::sort(sortedClusters3D.begin(), sortedClusters3D.end(), LArClusterHelper::SortByNHits);
207 
208  ClusterSet usedClusters;
209 
210  for (const Cluster *const pCluster3D : sortedClusters3D)
211  {
212  if (usedClusters.count(pCluster3D))
213  continue;
214 
215  if (pCluster3D->GetNCaloHits() < m_min3DHitsToSeedNewSlice)
216  continue;
217 
218  clusterSliceList.push_back(ClusterVector(1, pCluster3D));
219  usedClusters.insert(pCluster3D);
220 
221  ClusterVector &clusterSlice(clusterSliceList.back());
222  this->CollectAssociatedClusters(pCluster3D, sortedClusters3D, trackFitResults, showerConeFitResults, clusterSlice, usedClusters);
223  }
224 }
225 
226 //------------------------------------------------------------------------------------------------------------------------------------------
227 
228 void EventSlicingTool::CollectAssociatedClusters(const Cluster *const pClusterInSlice, const ClusterVector &candidateClusters,
229  const ThreeDSlidingFitResultMap &trackFitResults, const ThreeDSlidingConeFitResultMap &showerConeFitResults,
230  ClusterVector &clusterSlice, ClusterSet &usedClusters) const
231 {
232  ClusterVector addedClusters;
233 
234  for (const Cluster *const pCandidateCluster : candidateClusters)
235  {
236  if (usedClusters.count(pCandidateCluster) || (pClusterInSlice == pCandidateCluster))
237  continue;
238 
239  if ((m_usePointingAssociation && this->PassPointing(pClusterInSlice, pCandidateCluster, trackFitResults)) ||
240  (m_useProximityAssociation && this->PassProximity(pClusterInSlice, pCandidateCluster)) ||
242  (this->PassShowerCone(pClusterInSlice, pCandidateCluster, showerConeFitResults) ||
243  this->PassShowerCone(pCandidateCluster, pClusterInSlice, showerConeFitResults))))
244  {
245  addedClusters.push_back(pCandidateCluster);
246  (void)usedClusters.insert(pCandidateCluster);
247  }
248  }
249 
250  clusterSlice.insert(clusterSlice.end(), addedClusters.begin(), addedClusters.end());
251 
252  for (const Cluster *const pAddedCluster : addedClusters)
253  this->CollectAssociatedClusters(pAddedCluster, candidateClusters, trackFitResults, showerConeFitResults, clusterSlice, usedClusters);
254 }
255 
256 //------------------------------------------------------------------------------------------------------------------------------------------
257 
259  const Cluster *const pClusterInSlice, const Cluster *const pCandidateCluster, const ThreeDSlidingFitResultMap &trackFitResults) const
260 {
261  ThreeDSlidingFitResultMap::const_iterator inSliceIter = trackFitResults.find(pClusterInSlice);
262  ThreeDSlidingFitResultMap::const_iterator candidateIter = trackFitResults.find(pCandidateCluster);
263 
264  if ((trackFitResults.end() == inSliceIter) || (trackFitResults.end() == candidateIter))
265  return false;
266 
267  const LArPointingCluster inSlicePointingCluster(inSliceIter->second);
268  const LArPointingCluster candidatePointingCluster(candidateIter->second);
269 
270  if (this->CheckClosestApproach(inSlicePointingCluster, candidatePointingCluster) ||
271  this->IsEmission(inSlicePointingCluster, candidatePointingCluster) || this->IsNode(inSlicePointingCluster, candidatePointingCluster))
272  {
273  return true;
274  }
275 
276  return false;
277 }
278 
279 //------------------------------------------------------------------------------------------------------------------------------------------
280 
281 bool EventSlicingTool::PassProximity(const Cluster *const pClusterInSlice, const Cluster *const pCandidateCluster) const
282 {
283  for (const auto &orderedList1 : pClusterInSlice->GetOrderedCaloHitList())
284  {
285  for (const CaloHit *const pCaloHit1 : *(orderedList1.second))
286  {
287  const CartesianVector &positionVector1(pCaloHit1->GetPositionVector());
288 
289  for (const auto &orderedList2 : pCandidateCluster->GetOrderedCaloHitList())
290  {
291  for (const CaloHit *const pCaloHit2 : *(orderedList2.second))
292  {
293  if ((positionVector1 - pCaloHit2->GetPositionVector()).GetMagnitudeSquared() < m_maxHitSeparationSquared)
294  return true;
295  }
296  }
297  }
298  }
299 
300  return false;
301 }
302 
303 //------------------------------------------------------------------------------------------------------------------------------------------
304 
306  const Cluster *const pConeCluster, const Cluster *const pNearbyCluster, const ThreeDSlidingConeFitResultMap &showerConeFitResults) const
307 {
308  ThreeDSlidingConeFitResultMap::const_iterator fitIter = showerConeFitResults.find(pConeCluster);
309 
310  if (showerConeFitResults.end() == fitIter)
311  return false;
312 
313  float clusterLength(0.f);
314  SimpleConeList simpleConeList;
315 
316  try
317  {
318  const ThreeDSlidingConeFitResult &slidingConeFitResult3D(fitIter->second);
319  const ThreeDSlidingFitResult &slidingFitResult3D(slidingConeFitResult3D.GetSlidingFitResult());
320  slidingConeFitResult3D.GetSimpleConeList(m_nConeFitLayers, m_nConeFits, CONE_BOTH_DIRECTIONS, simpleConeList);
321  clusterLength = (slidingFitResult3D.GetGlobalMaxLayerPosition() - slidingFitResult3D.GetGlobalMinLayerPosition()).GetMagnitude();
322  }
323  catch (const StatusCodeException &)
324  {
325  return false;
326  }
327 
328  for (const SimpleCone &simpleCone : simpleConeList)
329  {
330  const float coneLength(std::min(m_coneLengthMultiplier * clusterLength, m_maxConeLength));
331 
332  if (simpleCone.GetBoundedHitFraction(pNearbyCluster, coneLength, m_coneTanHalfAngle1) < m_coneBoundedFraction1)
333  continue;
334 
335  if (simpleCone.GetBoundedHitFraction(pNearbyCluster, coneLength, m_coneTanHalfAngle2) < m_coneBoundedFraction2)
336  continue;
337 
338  return true;
339  }
340 
341  return false;
342 }
343 
344 //------------------------------------------------------------------------------------------------------------------------------------------
345 
347 {
348  return (this->CheckClosestApproach(cluster1.GetInnerVertex(), cluster2.GetInnerVertex()) ||
349  this->CheckClosestApproach(cluster1.GetOuterVertex(), cluster2.GetInnerVertex()) ||
350  this->CheckClosestApproach(cluster1.GetInnerVertex(), cluster2.GetOuterVertex()) ||
351  this->CheckClosestApproach(cluster1.GetOuterVertex(), cluster2.GetOuterVertex()));
352 }
353 
354 //------------------------------------------------------------------------------------------------------------------------------------------
355 
357 {
358  CartesianVector intersectionPoint(0.f, 0.f, 0.f);
359  float displacement1(std::numeric_limits<float>::max()), displacement2(std::numeric_limits<float>::max());
360 
361  try
362  {
363  LArPointingClusterHelper::GetIntersection(vertex1, vertex2, intersectionPoint, displacement1, displacement2);
364  }
365  catch (const StatusCodeException &)
366  {
367  return false;
368  }
369 
370  const CartesianVector approach1(vertex1.GetPosition() + vertex1.GetDirection() * displacement1);
371  const CartesianVector approach2(vertex2.GetPosition() + vertex2.GetDirection() * displacement2);
372  const float closestApproach((approach1 - approach2).GetMagnitude());
373 
374  return ((closestApproach < m_maxClosestApproach) && (std::fabs(displacement1) < m_maxInterceptDistance) &&
375  (std::fabs(displacement2) < m_maxInterceptDistance));
376 }
377 
378 //------------------------------------------------------------------------------------------------------------------------------------------
379 
380 bool EventSlicingTool::IsNode(const LArPointingCluster &cluster1, const LArPointingCluster &cluster2) const
381 {
398 }
399 
400 //------------------------------------------------------------------------------------------------------------------------------------------
401 
402 bool EventSlicingTool::IsEmission(const LArPointingCluster &cluster1, const LArPointingCluster &cluster2) const
403 {
420 }
421 
422 //------------------------------------------------------------------------------------------------------------------------------------------
423 
424 void EventSlicingTool::CreateSlices(const ClusterSliceList &clusterSliceList, SliceList &sliceList, ClusterToSliceIndexMap &clusterToSliceIndexMap) const
425 {
426  unsigned int index(0);
427 
428  for (const ClusterVector &clusterList : clusterSliceList)
429  {
430  for (const Cluster *const pCluster3D : clusterList)
431  {
432  if (TPC_3D != LArClusterHelper::GetClusterHitType(pCluster3D))
433  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
434 
435  if (!clusterToSliceIndexMap.insert(ClusterToSliceIndexMap::value_type(pCluster3D, index)).second)
436  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
437  }
438 
439  sliceList.push_back(Slice());
440  ++index;
441  }
442 }
443 
444 //------------------------------------------------------------------------------------------------------------------------------------------
445 
446 void EventSlicingTool::CopyPfoHitsToSlices(const ClusterToSliceIndexMap &clusterToSliceIndexMap, const ClusterToPfoMap &clusterToPfoMap,
447  SliceList &sliceList, ClusterSet &assignedClusters) const
448 {
449  ClusterList clusterList;
450  for (const auto &mapEntry : clusterToSliceIndexMap)
451  clusterList.push_back(mapEntry.first);
452  clusterList.sort(LArClusterHelper::SortByNHits);
453 
454  for (const Cluster *const pCluster3D : clusterList)
455  {
456  const unsigned int index(clusterToSliceIndexMap.at(pCluster3D));
457 
458  const Pfo *const pPfo(clusterToPfoMap.at(pCluster3D));
459  Slice &slice(sliceList.at(index));
460 
461  ClusterList clusters2D;
462  LArPfoHelper::GetTwoDClusterList(pPfo, clusters2D);
463 
464  for (const Cluster *const pCluster2D : clusters2D)
465  {
466  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster2D));
467 
468  if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
469  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
470 
471  CaloHitList &targetList((TPC_VIEW_U == hitType) ? slice.m_caloHitListU
472  : (TPC_VIEW_V == hitType) ? slice.m_caloHitListV
473  : slice.m_caloHitListW);
474 
475  pCluster2D->GetOrderedCaloHitList().FillCaloHitList(targetList);
476  targetList.insert(targetList.end(), pCluster2D->GetIsolatedCaloHitList().begin(), pCluster2D->GetIsolatedCaloHitList().end());
477 
478  if (!assignedClusters.insert(pCluster2D).second)
479  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
480  }
481  }
482 }
483 
484 //------------------------------------------------------------------------------------------------------------------------------------------
485 
486 void EventSlicingTool::GetRemainingClusters(const Algorithm *const pAlgorithm, const HitTypeToNameMap &clusterListNames,
487  const ClusterSet &assignedClusters, ClusterList &remainingClusters) const
488 {
489  this->GetRemainingClusters(pAlgorithm, clusterListNames.at(TPC_VIEW_U), assignedClusters, remainingClusters);
490  this->GetRemainingClusters(pAlgorithm, clusterListNames.at(TPC_VIEW_V), assignedClusters, remainingClusters);
491  this->GetRemainingClusters(pAlgorithm, clusterListNames.at(TPC_VIEW_W), assignedClusters, remainingClusters);
492 }
493 
494 //------------------------------------------------------------------------------------------------------------------------------------------
495 
496 void EventSlicingTool::GetRemainingClusters(const Algorithm *const pAlgorithm, const std::string &clusterListName,
497  const ClusterSet &assignedClusters, ClusterList &remainingClusters) const
498 {
499  const ClusterList *pClusterList(nullptr);
500  PANDORA_THROW_RESULT_IF_AND_IF(
501  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*pAlgorithm, clusterListName, pClusterList));
502 
503  if (!pClusterList || pClusterList->empty())
504  {
505  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
506  std::cout << "EventSlicingTool: unable to find cluster list " << clusterListName << std::endl;
507 
508  return;
509  }
510 
511  for (const Cluster *const pCluster2D : *pClusterList)
512  {
513  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster2D));
514 
515  if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
516  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
517 
518  if (assignedClusters.count(pCluster2D))
519  continue;
520 
521  if (remainingClusters.end() != std::find(remainingClusters.begin(), remainingClusters.end(), pCluster2D))
522  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
523 
524  remainingClusters.push_back(pCluster2D);
525  }
526 }
527 
528 //------------------------------------------------------------------------------------------------------------------------------------------
529 
531  const ClusterList &remainingClusters, const ClusterToSliceIndexMap &clusterToSliceIndexMap, SliceList &sliceList) const
532 {
533  PointToSliceIndexMap pointToSliceIndexMap;
534 
535  try
536  {
537  PointList pointsU, pointsV, pointsW;
538  this->GetKDTreeEntries2D(sliceList, pointsU, pointsV, pointsW, pointToSliceIndexMap);
539 
541  this->GetKDTreeEntries3D(clusterToSliceIndexMap, pointsU, pointsV, pointsW, pointToSliceIndexMap);
542 
543  pointsU.sort(EventSlicingTool::SortPoints);
544  pointsV.sort(EventSlicingTool::SortPoints);
545  pointsW.sort(EventSlicingTool::SortPoints);
546 
547  PointKDNode2DList kDNode2DListU, kDNode2DListV, kDNode2DListW;
548  KDTreeBox boundingRegionU = fill_and_bound_2d_kd_tree(pointsU, kDNode2DListU);
549  KDTreeBox boundingRegionV = fill_and_bound_2d_kd_tree(pointsV, kDNode2DListV);
550  KDTreeBox boundingRegionW = fill_and_bound_2d_kd_tree(pointsW, kDNode2DListW);
551 
552  PointKDTree2D kdTreeU, kdTreeV, kdTreeW;
553  kdTreeU.build(kDNode2DListU, boundingRegionU);
554  kdTreeV.build(kDNode2DListV, boundingRegionV);
555  kdTreeW.build(kDNode2DListW, boundingRegionW);
556 
557  ClusterVector sortedRemainingClusters(remainingClusters.begin(), remainingClusters.end());
558  std::sort(sortedRemainingClusters.begin(), sortedRemainingClusters.end(), LArClusterHelper::SortByNHits);
559 
560  for (const Cluster *const pCluster2D : sortedRemainingClusters)
561  {
562  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster2D));
563 
564  if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
565  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
566 
567  PointKDTree2D &kdTree((TPC_VIEW_U == hitType) ? kdTreeU : (TPC_VIEW_V == hitType) ? kdTreeV : kdTreeW);
568  const PointKDNode2D *pBestResultPoint(this->MatchClusterToSlice(pCluster2D, kdTree));
569 
570  if (!pBestResultPoint)
571  continue;
572 
573  Slice &slice(sliceList.at(pointToSliceIndexMap.at(pBestResultPoint->data)));
574  CaloHitList &targetList((TPC_VIEW_U == hitType) ? slice.m_caloHitListU
575  : (TPC_VIEW_V == hitType) ? slice.m_caloHitListV
576  : slice.m_caloHitListW);
577 
578  pCluster2D->GetOrderedCaloHitList().FillCaloHitList(targetList);
579  targetList.insert(targetList.end(), pCluster2D->GetIsolatedCaloHitList().begin(), pCluster2D->GetIsolatedCaloHitList().end());
580  }
581  }
582  catch (...)
583  {
584  std::cout << "EventSlicingTool::AssignRemainingHitsToSlices - exception " << std::endl;
585  for (const auto &pointMap : pointToSliceIndexMap)
586  delete pointMap.first;
587  throw;
588  }
589 
590  for (const auto &pointMap : pointToSliceIndexMap)
591  delete pointMap.first;
592 }
593 
594 //------------------------------------------------------------------------------------------------------------------------------------------
595 
597  const SliceList &sliceList, PointList &pointsU, PointList &pointsV, PointList &pointsW, PointToSliceIndexMap &pointToSliceIndexMap) const
598 {
599  unsigned int sliceIndex(0);
600 
601  for (const Slice &slice : sliceList)
602  {
603  for (const CaloHit *const pCaloHit : slice.m_caloHitListU)
604  {
605  const CartesianVector *const pPoint(new CartesianVector(pCaloHit->GetPositionVector()));
606  pointToSliceIndexMap.insert(PointToSliceIndexMap::value_type(pPoint, sliceIndex));
607  pointsU.push_back(pPoint);
608  }
609 
610  for (const CaloHit *const pCaloHit : slice.m_caloHitListV)
611  {
612  const CartesianVector *const pPoint(new CartesianVector(pCaloHit->GetPositionVector()));
613  pointToSliceIndexMap.insert(PointToSliceIndexMap::value_type(pPoint, sliceIndex));
614  pointsV.push_back(pPoint);
615  }
616 
617  for (const CaloHit *const pCaloHit : slice.m_caloHitListW)
618  {
619  const CartesianVector *const pPoint(new CartesianVector(pCaloHit->GetPositionVector()));
620  pointToSliceIndexMap.insert(PointToSliceIndexMap::value_type(pPoint, sliceIndex));
621  pointsW.push_back(pPoint);
622  }
623 
624  ++sliceIndex;
625  }
626 }
627 
628 //------------------------------------------------------------------------------------------------------------------------------------------
629 
630 void EventSlicingTool::GetKDTreeEntries3D(const ClusterToSliceIndexMap &clusterToSliceIndexMap, PointList &pointsU, PointList &pointsV,
631  PointList &pointsW, PointToSliceIndexMap &pointToSliceIndexMap) const
632 {
633  ClusterList clusterList;
634  for (const auto &mapEntry : clusterToSliceIndexMap)
635  clusterList.push_back(mapEntry.first);
636  clusterList.sort(LArClusterHelper::SortByNHits);
637 
638  for (const Cluster *const pCluster3D : clusterList)
639  {
640  const unsigned int sliceIndex(clusterToSliceIndexMap.at(pCluster3D));
641 
642  CaloHitList caloHitList;
643  pCluster3D->GetOrderedCaloHitList().FillCaloHitList(caloHitList);
644 
645  for (const CaloHit *const pCaloHit3D : caloHitList)
646  {
647  if (TPC_3D != pCaloHit3D->GetHitType())
648  throw StatusCodeException(STATUS_CODE_FAILURE);
649 
650  const CartesianVector &position3D(pCaloHit3D->GetPositionVector());
651 
652  const CartesianVector *const pProjectionU(
653  new CartesianVector(LArGeometryHelper::ProjectPosition(this->GetPandora(), position3D, TPC_VIEW_U)));
654  const CartesianVector *const pProjectionV(
655  new CartesianVector(LArGeometryHelper::ProjectPosition(this->GetPandora(), position3D, TPC_VIEW_V)));
656  const CartesianVector *const pProjectionW(
657  new CartesianVector(LArGeometryHelper::ProjectPosition(this->GetPandora(), position3D, TPC_VIEW_W)));
658 
659  pointsU.push_back(pProjectionU);
660  pointsV.push_back(pProjectionV);
661  pointsW.push_back(pProjectionW);
662 
663  pointToSliceIndexMap.insert(PointToSliceIndexMap::value_type(pProjectionU, sliceIndex));
664  pointToSliceIndexMap.insert(PointToSliceIndexMap::value_type(pProjectionV, sliceIndex));
665  pointToSliceIndexMap.insert(PointToSliceIndexMap::value_type(pProjectionW, sliceIndex));
666  }
667  }
668 }
669 
670 //------------------------------------------------------------------------------------------------------------------------------------------
671 
672 const EventSlicingTool::PointKDNode2D *EventSlicingTool::MatchClusterToSlice(const Cluster *const pCluster2D, PointKDTree2D &kdTree) const
673 {
674  PointList clusterPointList;
675  const PointKDNode2D *pBestResultPoint(nullptr);
676 
677  try
678  {
679  clusterPointList.push_back(new CartesianVector(pCluster2D->GetCentroid(pCluster2D->GetInnerPseudoLayer())));
680  clusterPointList.push_back(new CartesianVector(pCluster2D->GetCentroid(pCluster2D->GetOuterPseudoLayer())));
681  clusterPointList.push_back(new CartesianVector(
682  (pCluster2D->GetCentroid(pCluster2D->GetInnerPseudoLayer()) + pCluster2D->GetCentroid(pCluster2D->GetOuterPseudoLayer())) * 0.5f));
683 
684  float bestDistance(std::numeric_limits<float>::max());
685 
686  for (const CartesianVector *const pClusterPoint : clusterPointList)
687  {
688  const PointKDNode2D *pResultPoint(nullptr);
689  float resultDistance(std::numeric_limits<float>::max());
690  const PointKDNode2D targetPoint(pClusterPoint, pClusterPoint->GetX(), pClusterPoint->GetZ());
691  kdTree.findNearestNeighbour(targetPoint, pResultPoint, resultDistance);
692 
693  if (pResultPoint && (resultDistance < bestDistance))
694  {
695  pBestResultPoint = pResultPoint;
696  bestDistance = resultDistance;
697  }
698  }
699  }
700  catch (...)
701  {
702  std::cout << "EventSlicingTool::MatchClusterToSlice - exception " << std::endl;
703  for (const CartesianVector *const pPoint : clusterPointList)
704  delete pPoint;
705  throw;
706  }
707 
708  for (const CartesianVector *const pPoint : clusterPointList)
709  delete pPoint;
710 
711  return pBestResultPoint;
712 }
713 
714 //------------------------------------------------------------------------------------------------------------------------------------------
715 
716 bool EventSlicingTool::SortPoints(const CartesianVector *const pLhs, const CartesianVector *const pRhs)
717 {
718  const CartesianVector deltaPosition(*pRhs - *pLhs);
719 
720  if (std::fabs(deltaPosition.GetZ()) > std::numeric_limits<float>::epsilon())
721  return (deltaPosition.GetZ() > std::numeric_limits<float>::epsilon());
722 
723  if (std::fabs(deltaPosition.GetX()) > std::numeric_limits<float>::epsilon())
724  return (deltaPosition.GetX() > std::numeric_limits<float>::epsilon());
725 
726  return (deltaPosition.GetY() > std::numeric_limits<float>::epsilon());
727 }
728 
729 //------------------------------------------------------------------------------------------------------------------------------------------
730 
731 StatusCode EventSlicingTool::ReadSettings(const TiXmlHandle xmlHandle)
732 {
733  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "TrackPfoListName", m_trackPfoListName));
734 
735  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "ShowerPfoListName", m_showerPfoListName));
736 
737  PANDORA_RETURN_RESULT_IF_AND_IF(
738  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinHitsPer3DCluster", m_minHitsPer3DCluster));
739 
740  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
741  XmlHelper::ReadValue(xmlHandle, "Min3DHitsToSeedNewSlice", m_min3DHitsToSeedNewSlice));
742 
743  PANDORA_RETURN_RESULT_IF_AND_IF(
744  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingFitHalfWindow", m_halfWindowLayers));
745 
746  PANDORA_RETURN_RESULT_IF_AND_IF(
747  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "UsePointingAssociation", m_usePointingAssociation));
748 
749  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
750  XmlHelper::ReadValue(xmlHandle, "MinVertexLongitudinalDistance", m_minVertexLongitudinalDistance));
751 
752  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
753  XmlHelper::ReadValue(xmlHandle, "MaxVertexLongitudinalDistance", m_maxVertexLongitudinalDistance));
754 
755  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
756  XmlHelper::ReadValue(xmlHandle, "MaxVertexTransverseDistance", m_maxVertexTransverseDistance));
757 
758  PANDORA_RETURN_RESULT_IF_AND_IF(
759  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "VertexAngularAllowance", m_vertexAngularAllowance));
760 
761  PANDORA_RETURN_RESULT_IF_AND_IF(
762  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxClosestApproach", m_maxClosestApproach));
763 
764  PANDORA_RETURN_RESULT_IF_AND_IF(
765  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxInterceptDistance", m_maxInterceptDistance));
766 
767  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
768  XmlHelper::ReadValue(xmlHandle, "UseProximityAssociation", m_useProximityAssociation));
769 
770  float maxHitSeparation = std::sqrt(m_maxHitSeparationSquared);
771  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxHitSeparation", maxHitSeparation));
772  m_maxHitSeparationSquared = maxHitSeparation * maxHitSeparation;
773 
774  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
775  XmlHelper::ReadValue(xmlHandle, "UseShowerConeAssociation", m_useShowerConeAssociation));
776 
777  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NConeFitLayers", m_nConeFitLayers));
778 
779  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NConeFits", m_nConeFits));
780 
781  PANDORA_RETURN_RESULT_IF_AND_IF(
782  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeLengthMultiplier", m_coneLengthMultiplier));
783 
784  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxConeLength", m_maxConeLength));
785 
786  PANDORA_RETURN_RESULT_IF_AND_IF(
787  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeTanHalfAngle1", m_coneTanHalfAngle1));
788 
789  PANDORA_RETURN_RESULT_IF_AND_IF(
790  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeBoundedFraction1", m_coneBoundedFraction1));
791 
792  PANDORA_RETURN_RESULT_IF_AND_IF(
793  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeTanHalfAngle2", m_coneTanHalfAngle2));
794 
795  PANDORA_RETURN_RESULT_IF_AND_IF(
796  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeBoundedFraction2", m_coneBoundedFraction2));
797 
798  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
799  XmlHelper::ReadValue(xmlHandle, "Use3DProjectionsInHitPickUp", m_use3DProjectionsInHitPickUp));
800 
801  return STATUS_CODE_SUCCESS;
802 }
803 
804 } // namespace lar_content
void GetThreeDClusters(const pandora::Algorithm *const pAlgorithm, const std::string &pfoListName, pandora::ClusterList &clusters3D, ClusterToPfoMap &clusterToPfoMap) const
Get the 3D clusters from a specified list of pfos, storing the 3D clusters in the provided list and p...
unsigned int m_nConeFits
The number of cone fits to perform, spread roughly uniformly along the shower length.
static bool SortByNHits(const pandora::Cluster *const pLhs, const pandora::Cluster *const pRhs)
Sort clusters by number of hits, then layer span, then inner layer, then position, then pulse-height.
void GetClusterSliceList(const pandora::ClusterList &trackClusters3D, const pandora::ClusterList &showerClusters3D, ClusterSliceList &clusterSliceList) const
Divide the provided lists of 3D track and shower clusters into slices.
unsigned int m_min3DHitsToSeedNewSlice
The minimum number of hits in a 3D cluster to seed a new slice.
Header file for the kd tree linker algo template class.
Header file for the pfo helper class.
float m_maxHitSeparationSquared
Proximity association: max distance allowed between the closest pair of hits.
unsigned int m_nConeFitLayers
The number of layers over which to sum fitted direction to obtain cone fit.
float m_coneTanHalfAngle2
The cone tan half angle to use when calculating bounded cluster fractions 2.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::unordered_map< const pandora::Cluster *, const pandora::ParticleFlowObject * > ClusterToPfoMap
float m_maxVertexTransverseDistance
Pointing association check: max transverse distance cut.
static bool IsEmission(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxLongitudinalDistance, const float maxTransverseDistance, const float angularAllowance)
Whether pointing vertex is emitted from a given position.
float m_coneBoundedFraction2
The minimum cluster bounded fraction for association 2.
std::string m_showerPfoListName
The name of the input shower pfo list.
static void GetIntersection(const LArPointingCluster::Vertex &firstVertex, const LArPointingCluster::Vertex &secondVertex, pandora::CartesianVector &intersectPosition, float &firstDisplacement, float &secondDisplacement)
Get intersection of two vertices.
static void GetTwoDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 2D clusters from an input pfo.
Class that implements the KDTree partition of 2D space and a closest point search algorithm...
void CopyPfoHitsToSlices(const ClusterToSliceIndexMap &clusterToSliceIndexMap, const ClusterToPfoMap &clusterToPfoMap, SliceList &sliceList, pandora::ClusterSet &assignedClusters) const
Use 3D clusters in the cluster slice list, find their parent pfos and assign all hits in all 2D clust...
Box structure used to define 2D field. It&#39;s used in KDTree building step to divide the detector space...
std::vector< SimpleCone > SimpleConeList
void CopyAllHitsToSingleSlice(const pandora::Algorithm *const pAlgorithm, const HitTypeToNameMap &caloHitListNames, SliceList &sliceList) const
Copy all the input hits in an event into a single slice.
bool PassShowerCone(const pandora::Cluster *const pConeCluster, const pandora::Cluster *const pNearbyCluster, const ThreeDSlidingConeFitResultMap &showerConeFitResults) const
Compare the provided clusters to assess whether they are associated via cone fits to the shower clust...
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
std::vector< Slice > SliceList
Definition: LArSlice.h:29
intermediate_table::const_iterator const_iterator
bool PassPointing(const pandora::Cluster *const pClusterInSlice, const pandora::Cluster *const pCandidateCluster, const ThreeDSlidingFitResultMap &trackFitResults) const
Compare the provided clusters to assess whether they are associated via pointing (checks association ...
const ThreeDSlidingFitResult & GetSlidingFitResult() const
Get the sliding fit result for the full cluster.
unsigned int m_minHitsPer3DCluster
The minimum number of hits in a 3D cluster to warrant consideration in slicing.
LArPointingCluster class.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
float m_coneTanHalfAngle1
The cone tan half angle to use when calculating bounded cluster fractions 1.
void CollectAssociatedClusters(const pandora::Cluster *const pClusterInSlice, const pandora::ClusterVector &candidateClusters, const ThreeDSlidingFitResultMap &trackFitResults, const ThreeDSlidingConeFitResultMap &showerConeFitResults, pandora::ClusterVector &clusterSlice, pandora::ClusterSet &usedClusters) const
Collect all clusters associated with a provided cluster.
const PointKDNode2D * MatchClusterToSlice(const pandora::Cluster *const pCluster2D, PointKDTree2D &kdTree) const
Use the provided kd tree to efficiently identify the most appropriate slice for the provided 2D clust...
pandora::CaloHitList m_caloHitListW
The w calo hit list.
Definition: LArSlice.h:26
Header file for the lar three dimensional sliding cone fit result class.
void GetSimpleConeList(const unsigned int nLayersForConeFit, const unsigned int nCones, const ConeSelection coneSelection, SimpleConeList &simpleConeList) const
Get the list of simple cones fitted to the three dimensional cluster.
float m_maxVertexLongitudinalDistance
Pointing association check: max longitudinal distance cut.
void findNearestNeighbour(const KDTreeNodeInfoT< DATA, DIM > &point, const KDTreeNodeInfoT< DATA, DIM > *&result, float &distance)
findNearestNeighbour
Data stored in each KDTree node. The dim1/dim2 fields are usually the duplication of some PFRecHit va...
std::unordered_map< const pandora::CartesianVector *, unsigned int > PointToSliceIndexMap
TFile f
Definition: plotHisto.C:6
std::string m_trackPfoListName
The name of the input track pfo list.
pandora::CaloHitList m_caloHitListU
The u calo hit list.
Definition: LArSlice.h:24
Header file for the geometry helper class.
bool m_useProximityAssociation
Whether to use proximity association.
float m_maxClosestApproach
Pointing association: max distance of closest approach between straight line fits.
pandora::CaloHitList m_caloHitListV
The v calo hit list.
Definition: LArSlice.h:25
std::unordered_map< const pandora::Cluster *, ThreeDSlidingFitResult > ThreeDSlidingFitResultMap
bool IsNode(const LArPointingCluster &cluster1, const LArPointingCluster &cluster2) const
Check whether a pair of pointing clusters are nodally associated.
static bool SortPoints(const pandora::CartesianVector *const pLhs, const pandora::CartesianVector *const pRhs)
Sort points (use Z, followed by X, followed by Y)
std::map< pandora::HitType, std::string > HitTypeToNameMap
Header file for the cluster helper class.
bool m_usePointingAssociation
Whether to use pointing association.
float m_coneLengthMultiplier
The cone length multiplier to use when calculating bounded cluster fractions.
const Vertex & GetOuterVertex() const
Get the outer vertex.
void build(std::vector< KDTreeNodeInfoT< DATA, DIM >> &eltList, const KDTreeBoxT< DIM > &region)
Build the KD tree from the "eltList" in the space define by "region".
const Vertex & GetInnerVertex() const
Get the inner vertex.
Header file for the event slicing tool class.
bool PassProximity(const pandora::Cluster *const pClusterInSlice, const pandora::Cluster *const pCandidateCluster) const
Compare the provided clusters to assess whether they are associated via pointing. ...
static float GetWirePitch(const pandora::Pandora &pandora, const pandora::HitType view, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
void GetKDTreeEntries2D(const SliceList &sliceList, PointList &pointsU, PointList &pointsV, PointList &pointsW, PointToSliceIndexMap &pointToSliceIndexMap) const
Use projections of 3D hits already assigned to slices to populate kd trees to aid assignment of remai...
static void GetThreeDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 3D clusters from an input pfo.
std::vector< pandora::ClusterVector > ClusterSliceList
Header file for the lar three dimensional sliding fit result class.
const pandora::CartesianVector & GetDirection() const
Get the vertex direction.
std::unordered_map< const pandora::Cluster *, ThreeDSlidingConeFitResult > ThreeDSlidingConeFitResultMap
std::list< const pandora::CartesianVector * > PointList
void RunSlicing(const pandora::Algorithm *const pAlgorithm, const HitTypeToNameMap &caloHitListNames, const HitTypeToNameMap &clusterListNames, SliceList &sliceList)
Run the slicing tool.
bool CheckClosestApproach(const LArPointingCluster &cluster1, const LArPointingCluster &cluster2) const
Check closest approach metrics for a pair of pointing clusters.
HitType
Definition: HitType.h:12
std::vector< PointKDNode2D > PointKDNode2DList
std::unordered_map< const pandora::Cluster *, unsigned int > ClusterToSliceIndexMap
float m_maxInterceptDistance
Pointing association: max distance from cluster vertex to point of closest approach.
void GetRemainingClusters(const pandora::Algorithm *const pAlgorithm, const HitTypeToNameMap &clusterListNames, const pandora::ClusterSet &assignedClusters, pandora::ClusterList &remainingClusters) const
Get the list of 2D clusters with hits yets to be assigned to slices.
KDTreeBox fill_and_bound_2d_kd_tree(const MANAGED_CONTAINER< const T * > &points, std::vector< KDTreeNodeInfoT< const T *, 2 >> &nodes)
fill_and_bound_2d_kd_tree
float m_minVertexLongitudinalDistance
Pointing association check: min longitudinal distance cut.
bool IsEmission(const LArPointingCluster &cluster1, const LArPointingCluster &cluster2) const
Check whether a pair of pointing clusters are consistent with an emission.
Slice class.
Definition: LArSlice.h:21
bool m_use3DProjectionsInHitPickUp
Whether to include 3D cluster projections when assigning remaining clusters to slices.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
float m_maxConeLength
The maximum allowed cone length to use when calculating bounded cluster fractions.
bool m_useShowerConeAssociation
Whether to use shower cone association.
float m_vertexAngularAllowance
Pointing association check: pointing angular allowance in degrees.
void CreateSlices(const ClusterSliceList &clusterSliceList, SliceList &sliceList, ClusterToSliceIndexMap &clusterToSliceIndexMap) const
Create new slices for each of the groupings of 3D clusters in the provided cluster slice list...
const pandora::CartesianVector & GetPosition() const
Get the vertex position.
void GetKDTreeEntries3D(const ClusterToSliceIndexMap &clusterToSliceIndexMap, PointList &pointsU, PointList &pointsV, PointList &pointsW, PointToSliceIndexMap &pointToSliceIndexMap) const
Use 2D hits already assigned to slices to populate kd trees to aid assignment of remaining clusters...
float m_coneBoundedFraction1
The minimum cluster bounded fraction for association 1.
void AssignRemainingHitsToSlices(const pandora::ClusterList &remainingClusters, const ClusterToSliceIndexMap &clusterToSliceIndexMap, SliceList &sliceList) const
Use the list of remaining 2D clusters to assign all remaining 2D hits to existing slices in the slice...
static bool IsNode(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxTransverseDistance)
Whether pointing vertex is adjacent to a given position.
unsigned int m_halfWindowLayers
The number of layers to use for half-window of sliding fit.