DeltaRayMatchingAlgorithm.cc
Go to the documentation of this file.
1 /**
2  * @file larpandoracontent/LArThreeDReco/LArCosmicRay/DeltaRayMatchingAlgorithm.cc
3  *
4  * @brief Implementation of the delta ray shower matching algorithm class.
5  *
6  * $Log: $
7  */
8 
9 #include "Pandora/AlgorithmHeaders.h"
10 
14 
16 
18 
19 using namespace pandora;
20 
21 namespace lar_content
22 {
23 
24 DeltaRayMatchingAlgorithm::DeltaRayMatchingAlgorithm() :
25  m_minCaloHitsPerCluster(3),
26  m_xOverlapWindow(1.f),
27  m_distanceForMatching(5.f),
28  m_pseudoChi2Cut(3.f),
29  m_searchRegion1D(5.f)
30 {
31 }
32 
33 //------------------------------------------------------------------------------------------------------------------------------------------
34 
36 {
37  PfoVector pfoVector;
38  this->GetAllPfos(m_parentPfoListName, pfoVector);
39 
40  if (pfoVector.empty())
41  {
42  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
43  std::cout << "DeltaRayMatchingAlgorithm: pfo list " << m_parentPfoListName << " unavailable." << std::endl;
44 
45  return STATUS_CODE_SUCCESS;
46  }
47 
49 
50  ClusterLengthMap clusterLengthMap;
51  this->ThreeViewMatching(clusterLengthMap);
52  this->TwoViewMatching(clusterLengthMap);
53  this->OneViewMatching(clusterLengthMap);
54 
55  this->ClearNearbyClusterMaps();
56 
57  return STATUS_CODE_SUCCESS;
58 }
59 
60 //------------------------------------------------------------------------------------------------------------------------------------------
61 
63 {
64  this->ClearNearbyClusterMaps();
68 }
69 
70 //------------------------------------------------------------------------------------------------------------------------------------------
71 
73 {
74  const ClusterList *pClusterList = NULL;
75  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this, clusterListName, pClusterList))
76 
77  if ((NULL == pClusterList) || pClusterList->empty())
78  return;
79 
80  HitToClusterMap hitToClusterMap;
81  CaloHitList allCaloHits;
82 
83  for (const Cluster *const pCluster : *pClusterList)
84  {
85  CaloHitList daughterHits;
86  pCluster->GetOrderedCaloHitList().FillCaloHitList(daughterHits);
87  allCaloHits.insert(allCaloHits.end(), daughterHits.begin(), daughterHits.end());
88 
89  for (const CaloHit *const pCaloHit : daughterHits)
90  (void)hitToClusterMap.insert(HitToClusterMap::value_type(pCaloHit, pCluster));
91  }
92 
93  HitKDTree2D kdTree;
94  HitKDNode2DList hitKDNode2DList;
95 
96  KDTreeBox hitsBoundingRegion2D(fill_and_bound_2d_kd_tree(allCaloHits, hitKDNode2DList));
97  kdTree.build(hitKDNode2DList, hitsBoundingRegion2D);
98 
99  for (const Cluster *const pCluster : *pClusterList)
100  {
101  CaloHitList daughterHits;
102  pCluster->GetOrderedCaloHitList().FillCaloHitList(daughterHits);
103 
104  for (const CaloHit *const pCaloHit : daughterHits)
105  {
107 
109  kdTree.search(searchRegionHits, found);
110 
111  for (const auto &hit : found)
112  {
113  ClusterList &nearbyClusterList(nearbyClusters[pCluster]);
114  const Cluster *const pNearbyCluster(hitToClusterMap.at(hit.data));
115 
116  if (nearbyClusterList.end() == std::find(nearbyClusterList.begin(), nearbyClusterList.end(), pNearbyCluster))
117  nearbyClusterList.push_back(pNearbyCluster);
118  }
119  }
120  }
121 }
122 
123 //------------------------------------------------------------------------------------------------------------------------------------------
124 
126 {
127  m_nearbyClustersU.clear();
128  m_nearbyClustersV.clear();
129  m_nearbyClustersW.clear();
130 }
131 
132 //------------------------------------------------------------------------------------------------------------------------------------------
133 
134 void DeltaRayMatchingAlgorithm::GetAllPfos(const std::string &inputPfoListName, PfoVector &pfoVector) const
135 {
136  const PfoList *pPfoList = NULL;
137  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this, inputPfoListName, pPfoList));
138 
139  if (NULL == pPfoList)
140  return;
141 
142  for (PfoList::const_iterator iter = pPfoList->begin(), iterEnd = pPfoList->end(); iter != iterEnd; ++iter)
143  pfoVector.push_back(*iter);
144 
145  std::sort(pfoVector.begin(), pfoVector.end(), LArPfoHelper::SortByNHits);
146 }
147 
148 //------------------------------------------------------------------------------------------------------------------------------------------
149 
150 void DeltaRayMatchingAlgorithm::GetTrackPfos(const std::string &inputPfoListName, PfoVector &pfoVector) const
151 {
152  PfoVector inputVector;
153  this->GetAllPfos(inputPfoListName, inputVector);
154 
155  for (PfoVector::const_iterator iter = inputVector.begin(), iterEnd = inputVector.end(); iter != iterEnd; ++iter)
156  {
157  const ParticleFlowObject *const pPfo = *iter;
158 
159  if (!LArPfoHelper::IsTrack(pPfo))
160  continue;
161 
162  pfoVector.push_back(pPfo);
163  }
164 
165  // ATTN Track pfo list is sorted only because the inputVector is sorted
166 }
167 
168 //------------------------------------------------------------------------------------------------------------------------------------------
169 
170 void DeltaRayMatchingAlgorithm::GetClusters(const std::string &inputClusterListName, pandora::ClusterVector &clusterVector) const
171 {
172  const ClusterList *pClusterList = NULL;
173  PANDORA_THROW_RESULT_IF_AND_IF(
174  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this, inputClusterListName, pClusterList))
175 
176  if (NULL == pClusterList)
177  return;
178 
179  for (ClusterList::const_iterator cIter = pClusterList->begin(), cIterEnd = pClusterList->end(); cIter != cIterEnd; ++cIter)
180  {
181  const Cluster *const pCluster = *cIter;
182 
183  if (!pCluster->IsAvailable() || (pCluster->GetNCaloHits() < m_minCaloHitsPerCluster))
184  continue;
185 
186  clusterVector.push_back(pCluster);
187  }
188 
189  std::sort(clusterVector.begin(), clusterVector.end(), LArClusterHelper::SortByNHits);
190 }
191 
192 //------------------------------------------------------------------------------------------------------------------------------------------
193 
195 {
196  ClusterVector clustersU, clustersV, clustersW;
197  this->GetClusters(m_inputClusterListNameU, clustersU);
198  this->GetClusters(m_inputClusterListNameV, clustersV);
199  this->GetClusters(m_inputClusterListNameW, clustersW);
200 
201  PfoLengthMap pfoLengthMap;
202  ParticleList initialParticleList, finalParticleList;
203  this->ThreeViewMatching(clustersU, clustersV, clustersW, clusterLengthMap, pfoLengthMap, initialParticleList);
204  this->SelectParticles(initialParticleList, clusterLengthMap, finalParticleList);
205  this->CreateParticles(finalParticleList);
206 }
207 
208 //------------------------------------------------------------------------------------------------------------------------------------------
209 
211 {
212  ClusterVector clustersU, clustersV, clustersW;
213  this->GetClusters(m_inputClusterListNameU, clustersU);
214  this->GetClusters(m_inputClusterListNameV, clustersV);
215  this->GetClusters(m_inputClusterListNameW, clustersW);
216 
217  PfoLengthMap pfoLengthMap;
218  ParticleList initialParticleList, finalParticleList;
219  this->TwoViewMatching(clustersU, clustersV, clusterLengthMap, pfoLengthMap, initialParticleList);
220  this->TwoViewMatching(clustersV, clustersW, clusterLengthMap, pfoLengthMap, initialParticleList);
221  this->TwoViewMatching(clustersW, clustersU, clusterLengthMap, pfoLengthMap, initialParticleList);
222  this->SelectParticles(initialParticleList, clusterLengthMap, finalParticleList);
223  this->CreateParticles(finalParticleList);
224 }
225 
226 //------------------------------------------------------------------------------------------------------------------------------------------
227 
229 {
230  ClusterVector clustersU, clustersV, clustersW;
231  this->GetClusters(m_inputClusterListNameU, clustersU);
232  this->GetClusters(m_inputClusterListNameV, clustersV);
233  this->GetClusters(m_inputClusterListNameW, clustersW);
234 
235  PfoLengthMap pfoLengthMap;
236  ParticleList initialParticleList, finalParticleList;
237  this->ThreeViewMatching(clustersU, clustersV, clustersW, clusterLengthMap, pfoLengthMap, initialParticleList);
238  this->OneViewMatching(clustersU, clusterLengthMap, pfoLengthMap, initialParticleList);
239  this->OneViewMatching(clustersV, clusterLengthMap, pfoLengthMap, initialParticleList);
240  this->OneViewMatching(clustersW, clusterLengthMap, pfoLengthMap, initialParticleList);
241  this->SelectParticles(initialParticleList, clusterLengthMap, finalParticleList);
242  this->CreateParticles(finalParticleList);
243 }
244 
245 //------------------------------------------------------------------------------------------------------------------------------------------
246 
247 void DeltaRayMatchingAlgorithm::ThreeViewMatching(const ClusterVector &clusters1, const ClusterVector &clusters2,
248  const ClusterVector &clusters3, ClusterLengthMap &clusterLengthMap, PfoLengthMap &pfoLengthMap, ParticleList &particleList) const
249 {
250  if (clusters1.empty() || clusters2.empty() || clusters3.empty())
251  return;
252 
253  for (const Cluster *const pCluster1 : clusters1)
254  {
255  if (!pCluster1->IsAvailable())
256  continue;
257 
258  for (const Cluster *const pCluster2 : clusters2)
259  {
260  if (!pCluster2->IsAvailable())
261  continue;
262 
263  for (const Cluster *const pCluster3 : clusters3)
264  {
265  if (!pCluster3->IsAvailable())
266  continue;
267 
268  if (!this->AreClustersMatched(pCluster1, pCluster2, pCluster3))
269  continue;
270 
271  const ParticleFlowObject *pBestPfo = NULL;
272  this->FindBestParentPfo(pCluster1, pCluster2, pCluster3, clusterLengthMap, pfoLengthMap, pBestPfo);
273 
274  // ATTN Need to record all matches when all three views are used
275  particleList.push_back(Particle(pCluster1, pCluster2, pCluster3, pBestPfo));
276  }
277  }
278  }
279 }
280 
281 //------------------------------------------------------------------------------------------------------------------------------------------
282 
283 void DeltaRayMatchingAlgorithm::TwoViewMatching(const ClusterVector &clusters1, const ClusterVector &clusters2,
284  ClusterLengthMap &clusterLengthMap, PfoLengthMap &pfoLengthMap, ParticleList &particleList) const
285 {
286  if (clusters1.empty() || clusters2.empty())
287  return;
288 
289  for (const Cluster *const pCluster1 : clusters1)
290  {
291  if (!pCluster1->IsAvailable())
292  continue;
293 
294  for (const Cluster *const pCluster2 : clusters2)
295  {
296  if (!pCluster2->IsAvailable())
297  continue;
298 
299  if (!this->AreClustersMatched(pCluster1, pCluster2, NULL))
300  continue;
301 
302  const ParticleFlowObject *pBestPfo = NULL;
303  this->FindBestParentPfo(pCluster1, pCluster2, NULL, clusterLengthMap, pfoLengthMap, pBestPfo);
304 
305  if (NULL == pBestPfo)
306  continue;
307 
308  particleList.push_back(Particle(pCluster1, pCluster2, NULL, pBestPfo));
309  }
310  }
311 }
312 
313 //------------------------------------------------------------------------------------------------------------------------------------------
314 
316  const ClusterVector &clusters, ClusterLengthMap &clusterLengthMap, PfoLengthMap &pfoLengthMap, ParticleList &particleList) const
317 {
318  if (clusters.empty())
319  return;
320 
321  for (const Cluster *const pCluster : clusters)
322  {
323  if (!pCluster->IsAvailable())
324  continue;
325 
326  const ParticleFlowObject *pBestPfo = NULL;
327  this->FindBestParentPfo(pCluster, NULL, NULL, clusterLengthMap, pfoLengthMap, pBestPfo);
328 
329  if (NULL == pBestPfo)
330  continue;
331 
332  particleList.push_back(Particle(pCluster, NULL, NULL, pBestPfo));
333  }
334 }
335 
336 //------------------------------------------------------------------------------------------------------------------------------------------
337 
338 void DeltaRayMatchingAlgorithm::SelectParticles(const ParticleList &initialParticles, ClusterLengthMap &clusterLengthMap, ParticleList &finalParticles) const
339 {
340  for (const Particle &particle1 : initialParticles)
341  {
342  bool isGoodParticle(true);
343 
344  for (const Particle &particle2 : initialParticles)
345  {
346  const bool commonU(particle1.GetClusterU() == particle2.GetClusterU());
347  const bool commonV(particle1.GetClusterV() == particle2.GetClusterV());
348  const bool commonW(particle1.GetClusterW() == particle2.GetClusterW());
349 
350  const bool ambiguousU(commonU && NULL != particle1.GetClusterU());
351  const bool ambiguousV(commonV && NULL != particle1.GetClusterV());
352  const bool ambiguousW(commonW && NULL != particle1.GetClusterW());
353 
354  if (commonU && commonV && commonW)
355  continue;
356 
357  if (ambiguousU || ambiguousV || ambiguousW)
358  {
359  if (particle2.GetNViews() > particle1.GetNViews())
360  {
361  isGoodParticle = false;
362  }
363  else if (particle2.GetNViews() == particle1.GetNViews() && NULL != particle2.GetParentPfo())
364  {
365  if ((NULL == particle1.GetParentPfo()) || (particle2.GetNCaloHits() > particle1.GetNCaloHits()) ||
366  (particle2.GetNCaloHits() == particle1.GetNCaloHits() &&
367  this->GetLength(particle2, clusterLengthMap) >= this->GetLength(particle1, clusterLengthMap)))
368  {
369  isGoodParticle = false;
370  }
371  }
372 
373  if (!isGoodParticle)
374  break;
375  }
376  }
377 
378  if (isGoodParticle && NULL != particle1.GetParentPfo())
379  finalParticles.push_back(particle1);
380  }
381 }
382 
383 //------------------------------------------------------------------------------------------------------------------------------------------
384 
386 {
387  PfoVector parentVector, daughterVector;
388  this->GetTrackPfos(m_parentPfoListName, parentVector);
389  this->GetAllPfos(m_daughterPfoListName, daughterVector);
390 
391  PfoList parentList(parentVector.begin(), parentVector.end());
392  PfoList daughterList(daughterVector.begin(), daughterVector.end());
393 
394  for (const Particle &particle : particleList)
395  {
396  const ParticleFlowObject *const pParentPfo = particle.GetParentPfo();
397 
398  if (NULL == pParentPfo)
399  continue;
400 
401  const Cluster *const pClusterU = particle.GetClusterU();
402  const Cluster *const pClusterV = particle.GetClusterV();
403  const Cluster *const pClusterW = particle.GetClusterW();
404 
405  if (NULL == pClusterU && NULL == pClusterV && NULL == pClusterW)
406  throw StatusCodeException(STATUS_CODE_FAILURE);
407 
408  ClusterList clusterList;
409 
410  if (pClusterU)
411  clusterList.push_back(pClusterU);
412 
413  if (pClusterV)
414  clusterList.push_back(pClusterV);
415 
416  if (pClusterW)
417  clusterList.push_back(pClusterW);
418 
419  if (parentList.end() != std::find(parentList.begin(), parentList.end(), pParentPfo))
420  {
421  this->CreateDaughterPfo(clusterList, pParentPfo);
422  }
423  else if (daughterList.end() != std::find(daughterList.begin(), daughterList.end(), pParentPfo))
424  {
425  this->AddToDaughterPfo(clusterList, pParentPfo);
426  }
427  else
428  {
429  throw StatusCodeException(STATUS_CODE_FAILURE);
430  }
431  }
432 }
433 
434 //------------------------------------------------------------------------------------------------------------------------------------------
435 
436 bool DeltaRayMatchingAlgorithm::AreClustersMatched(const Cluster *const pCluster1, const Cluster *const pCluster2, const Cluster *const pCluster3) const
437 {
438  if (nullptr == pCluster1 && nullptr == pCluster2 && nullptr == pCluster3)
439  throw StatusCodeException(STATUS_CODE_FAILURE);
440 
441  // First step: Check X overlap
445 
446  if (nullptr != pCluster1)
447  pCluster1->GetClusterSpanX(xMin1, xMax1);
448 
449  if (nullptr != pCluster2)
450  pCluster2->GetClusterSpanX(xMin2, xMax2);
451 
452  if (nullptr != pCluster3)
453  pCluster3->GetClusterSpanX(xMin3, xMax3);
454 
455  const float xPitch(0.5 * m_xOverlapWindow);
456  const float xMin(std::max(xMin1, std::max(xMin2, xMin3)) - xPitch);
457  const float xMax(std::min(xMax1, std::min(xMax2, xMax3)) + xPitch);
458  const float xOverlap(xMax - xMin);
459 
460  if (xOverlap < std::numeric_limits<float>::epsilon())
461  return false;
462 
463  if (nullptr == pCluster1 || nullptr == pCluster2 || nullptr == pCluster3)
464  return true;
465 
466  // Second step: Check 3D matching
467  const HitType hitType1(LArClusterHelper::GetClusterHitType(pCluster1));
468  const HitType hitType2(LArClusterHelper::GetClusterHitType(pCluster2));
469  const HitType hitType3(LArClusterHelper::GetClusterHitType(pCluster3));
470 
471  if (hitType1 == hitType2 || hitType2 == hitType3 || hitType3 == hitType1)
472  throw StatusCodeException(STATUS_CODE_FAILURE);
473 
474  const unsigned int nSamplingPoints(1 + static_cast<unsigned int>(xOverlap / xPitch));
475 
476  for (unsigned int n = 0; n < nSamplingPoints; ++n)
477  {
478  const float x(xMin + (xMax - xMin) * (static_cast<float>(n) + 0.5f) / static_cast<float>(nSamplingPoints));
479  const float xmin(x - xPitch);
480  const float xmax(x + xPitch);
481 
482  try
483  {
484  float zMin1(0.f), zMin2(0.f), zMin3(0.f), zMax1(0.f), zMax2(0.f), zMax3(0.f);
485  pCluster1->GetClusterSpanZ(xmin, xmax, zMin1, zMax1);
486  pCluster2->GetClusterSpanZ(xmin, xmax, zMin2, zMax2);
487  pCluster3->GetClusterSpanZ(xmin, xmax, zMin3, zMax3);
488 
489  const float z1(0.5f * (zMin1 + zMax1));
490  const float z2(0.5f * (zMin2 + zMax2));
491  const float z3(0.5f * (zMin3 + zMax3));
492 
493  const float dz1(zMax1 - zMin1);
494  const float dz2(zMax2 - zMin2);
495  const float dz3(zMax3 - zMin3);
496  const float dz4(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
497 
498  const float zproj1(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType2, hitType3, z2, z3));
499  const float zproj2(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType3, hitType1, z3, z1));
500  const float zproj3(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType1, hitType2, z1, z2));
501 
502  const float deltaSquared(((z1 - zproj1) * (z1 - zproj1) + (z2 - zproj2) * (z2 - zproj2) + (z3 - zproj3) * (z3 - zproj3)) / 3.f);
503  const float sigmaSquared(dz1 * dz1 + dz2 * dz2 + dz3 * dz3 + dz4 * dz4);
504  const float pseudoChi2(deltaSquared / sigmaSquared);
505 
506  if (pseudoChi2 < m_pseudoChi2Cut)
507  return true;
508  }
509  catch (StatusCodeException &statusCodeException)
510  {
511  if (STATUS_CODE_NOT_FOUND != statusCodeException.GetStatusCode())
512  throw statusCodeException;
513  }
514  }
515 
516  return false;
517 }
518 
519 //------------------------------------------------------------------------------------------------------------------------------------------
520 
521 void DeltaRayMatchingAlgorithm::FindBestParentPfo(const Cluster *const pCluster1, const Cluster *const pCluster2,
522  const Cluster *const pCluster3, ClusterLengthMap &clusterLengthMap, PfoLengthMap &pfoLengthMap, const ParticleFlowObject *&pBestPfo) const
523 {
524  PfoVector pfoVector;
525  this->GetTrackPfos(m_parentPfoListName, pfoVector);
526  this->GetAllPfos(m_daughterPfoListName, pfoVector);
527 
528  if (pfoVector.empty())
529  throw StatusCodeException(STATUS_CODE_FAILURE);
530 
531  unsigned int numViews(0);
532  float lengthSquared(0.f);
533 
534  if (pCluster1)
535  {
536  lengthSquared += this->GetLengthFromCache(pCluster1, clusterLengthMap);
537  ++numViews;
538  }
539 
540  if (pCluster2)
541  {
542  lengthSquared += this->GetLengthFromCache(pCluster2, clusterLengthMap);
543  ++numViews;
544  }
545 
546  if (pCluster3)
547  {
548  lengthSquared += this->GetLengthFromCache(pCluster3, clusterLengthMap);
549  ++numViews;
550  }
551 
552  float bestDistanceSquared(static_cast<float>(numViews) * m_distanceForMatching * m_distanceForMatching);
553 
554  for (const ParticleFlowObject *const pPfo : pfoVector)
555  {
556  if (lengthSquared > this->GetLengthFromCache(pPfo, pfoLengthMap))
557  continue;
558 
559  try
560  {
561  float distanceSquared(0.f);
562 
563  if (NULL != pCluster1)
564  distanceSquared += this->GetDistanceSquaredToPfo(pCluster1, pPfo);
565 
566  if (NULL != pCluster2)
567  distanceSquared += this->GetDistanceSquaredToPfo(pCluster2, pPfo);
568 
569  if (NULL != pCluster3)
570  distanceSquared += this->GetDistanceSquaredToPfo(pCluster3, pPfo);
571 
572  if (distanceSquared < bestDistanceSquared)
573  {
574  pBestPfo = pPfo;
575  bestDistanceSquared = distanceSquared;
576  }
577  }
578  catch (StatusCodeException &statusCodeException)
579  {
580  if (!(STATUS_CODE_NOT_FOUND == statusCodeException.GetStatusCode()))
581  throw statusCodeException;
582  }
583  }
584 }
585 
586 //------------------------------------------------------------------------------------------------------------------------------------------
587 
588 float DeltaRayMatchingAlgorithm::GetLengthFromCache(const Cluster *const pCluster, ClusterLengthMap &clusterLengthMap) const
589 {
590  ClusterLengthMap::const_iterator iter = clusterLengthMap.find(pCluster);
591 
592  if (clusterLengthMap.end() != iter)
593  return iter->second;
594 
595  const float lengthSquared(LArClusterHelper::GetLengthSquared(pCluster));
596  (void)clusterLengthMap.insert(ClusterLengthMap::value_type(pCluster, lengthSquared));
597  return lengthSquared;
598 }
599 
600 //------------------------------------------------------------------------------------------------------------------------------------------
601 
602 float DeltaRayMatchingAlgorithm::GetLengthFromCache(const ParticleFlowObject *const pPfo, PfoLengthMap &pfoLengthMap) const
603 {
604  PfoLengthMap::const_iterator iter = pfoLengthMap.find(pPfo);
605 
606  if (pfoLengthMap.end() != iter)
607  return iter->second;
608 
609  const float lengthSquared(LArPfoHelper::GetTwoDLengthSquared(pPfo));
610  (void)pfoLengthMap.insert(PfoLengthMap::value_type(pPfo, lengthSquared));
611  return lengthSquared;
612 }
613 
614 //------------------------------------------------------------------------------------------------------------------------------------------
615 
616 float DeltaRayMatchingAlgorithm::GetLength(const Particle &particle, ClusterLengthMap &clusterLengthMap) const
617 {
618  float lengthSquared(0.f);
619 
620  if (particle.GetClusterU())
621  lengthSquared += this->GetLengthFromCache(particle.GetClusterU(), clusterLengthMap);
622 
623  if (particle.GetClusterV())
624  lengthSquared += this->GetLengthFromCache(particle.GetClusterV(), clusterLengthMap);
625 
626  if (particle.GetClusterW())
627  lengthSquared += this->GetLengthFromCache(particle.GetClusterW(), clusterLengthMap);
628 
629  return lengthSquared;
630 }
631 
632 //------------------------------------------------------------------------------------------------------------------------------------------
633 
634 float DeltaRayMatchingAlgorithm::GetDistanceSquaredToPfo(const Cluster *const pCluster, const ParticleFlowObject *const pPfo) const
635 {
636  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster));
637 
638  if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
639  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
640 
641  ClusterList comparisonList;
642  const ClusterToClustersMap &nearbyClusters((TPC_VIEW_U == hitType) ? m_nearbyClustersU : (TPC_VIEW_V == hitType) ? m_nearbyClustersV : m_nearbyClustersW);
643 
644  if (!nearbyClusters.count(pCluster))
646 
647  ClusterList pfoClusterList;
648  LArPfoHelper::GetClusters(pPfo, hitType, pfoClusterList);
649 
650  for (const Cluster *const pPfoCluster : pfoClusterList)
651  {
652  const ClusterList &clusterList(nearbyClusters.at(pCluster));
653 
654  if ((clusterList.end() != std::find(clusterList.begin(), clusterList.end(), pPfoCluster)) &&
655  (comparisonList.end() == std::find(comparisonList.begin(), comparisonList.end(), pPfoCluster)))
656  {
657  comparisonList.push_back(pPfoCluster);
658  }
659  }
660 
661  if (comparisonList.empty())
663 
664  return LArClusterHelper::GetClosestDistance(pCluster, comparisonList);
665 }
666 
667 //------------------------------------------------------------------------------------------------------------------------------------------
668 
669 void DeltaRayMatchingAlgorithm::CreateDaughterPfo(const ClusterList &clusterList, const ParticleFlowObject *const pParentPfo) const
670 {
671  const PfoList *pPfoList = NULL;
672  std::string pfoListName;
673  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pPfoList, pfoListName));
674 
675  // TODO Correct these placeholder parameters
676  PandoraContentApi::ParticleFlowObject::Parameters pfoParameters;
677  pfoParameters.m_particleId = E_MINUS; // SHOWER
678  pfoParameters.m_charge = PdgTable::GetParticleCharge(pfoParameters.m_particleId.Get());
679  pfoParameters.m_mass = PdgTable::GetParticleMass(pfoParameters.m_particleId.Get());
680  pfoParameters.m_energy = 0.f;
681  pfoParameters.m_momentum = CartesianVector(0.f, 0.f, 0.f);
682  pfoParameters.m_clusterList = clusterList;
683 
684  const ParticleFlowObject *pDaughterPfo(NULL);
685  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::Create(*this, pfoParameters, pDaughterPfo));
686 
687  if (!pPfoList->empty())
688  {
689  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Pfo>(*this, m_daughterPfoListName));
690  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SetPfoParentDaughterRelationship(*this, pParentPfo, pDaughterPfo));
691  }
692 }
693 
694 //------------------------------------------------------------------------------------------------------------------------------------------
695 
696 void DeltaRayMatchingAlgorithm::AddToDaughterPfo(const ClusterList &clusterList, const ParticleFlowObject *const pParentPfo) const
697 {
698  for (const Cluster *const pDaughterCluster : clusterList)
699  {
700  const HitType hitType(LArClusterHelper::GetClusterHitType(pDaughterCluster));
701  const std::string clusterListName(
702  (TPC_VIEW_U == hitType) ? m_inputClusterListNameU : (TPC_VIEW_V == hitType) ? m_inputClusterListNameV : m_inputClusterListNameW);
703 
704  ClusterList pfoClusters;
705  LArPfoHelper::GetClusters(pParentPfo, hitType, pfoClusters);
706 
707  if (pfoClusters.empty())
708  throw StatusCodeException(STATUS_CODE_FAILURE);
709 
710  const Cluster *const pParentCluster = *(pfoClusters.begin());
711 
712  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=,
713  PandoraContentApi::MergeAndDeleteClusters(*this, pParentCluster, pDaughterCluster, clusterListName, clusterListName));
714  }
715 }
716 
717 //------------------------------------------------------------------------------------------------------------------------------------------
718 //------------------------------------------------------------------------------------------------------------------------------------------
719 
721  const Cluster *const pCluster1, const Cluster *const pCluster2, const Cluster *const pCluster3, const ParticleFlowObject *const pPfo) :
722  m_pClusterU(NULL),
723  m_pClusterV(NULL),
724  m_pClusterW(NULL),
725  m_pParentPfo(NULL)
726 {
727  const HitType hitType1(NULL != pCluster1 ? LArClusterHelper::GetClusterHitType(pCluster1) : HIT_CUSTOM);
728  const HitType hitType2(NULL != pCluster2 ? LArClusterHelper::GetClusterHitType(pCluster2) : HIT_CUSTOM);
729  const HitType hitType3(NULL != pCluster3 ? LArClusterHelper::GetClusterHitType(pCluster3) : HIT_CUSTOM);
730 
731  m_pClusterU = ((TPC_VIEW_U == hitType1) ? pCluster1 : (TPC_VIEW_U == hitType2) ? pCluster2 : (TPC_VIEW_U == hitType3) ? pCluster3 : NULL);
732  m_pClusterV = ((TPC_VIEW_V == hitType1) ? pCluster1 : (TPC_VIEW_V == hitType2) ? pCluster2 : (TPC_VIEW_V == hitType3) ? pCluster3 : NULL);
733  m_pClusterW = ((TPC_VIEW_W == hitType1) ? pCluster1 : (TPC_VIEW_W == hitType2) ? pCluster2 : (TPC_VIEW_W == hitType3) ? pCluster3 : NULL);
734  m_pParentPfo = pPfo;
735 
736  if (NULL == m_pClusterU && NULL == m_pClusterV && NULL == m_pClusterW)
737  throw StatusCodeException(STATUS_CODE_FAILURE);
738 }
739 
740 //------------------------------------------------------------------------------------------------------------------------------------------
741 
743 {
744  unsigned int numViews(0);
745 
746  if (NULL != m_pClusterU)
747  numViews += 1;
748 
749  if (NULL != m_pClusterV)
750  numViews += 1;
751 
752  if (NULL != m_pClusterW)
753  numViews += 1;
754 
755  return numViews;
756 }
757 
758 //------------------------------------------------------------------------------------------------------------------------------------------
759 
761 {
762  unsigned int numCaloHits(0);
763 
764  if (NULL != m_pClusterU)
765  numCaloHits += m_pClusterU->GetNCaloHits();
766 
767  if (NULL != m_pClusterV)
768  numCaloHits += m_pClusterV->GetNCaloHits();
769 
770  if (NULL != m_pClusterW)
771  numCaloHits += m_pClusterW->GetNCaloHits();
772 
773  return numCaloHits;
774 }
775 
776 //------------------------------------------------------------------------------------------------------------------------------------------
777 //------------------------------------------------------------------------------------------------------------------------------------------
778 
779 StatusCode DeltaRayMatchingAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
780 {
781  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "ParentPfoListName", m_parentPfoListName));
782  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "DaughterPfoListName", m_daughterPfoListName));
783  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameU", m_inputClusterListNameU));
784  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameV", m_inputClusterListNameV));
785  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameW", m_inputClusterListNameW));
786 
787  PANDORA_RETURN_RESULT_IF_AND_IF(
788  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinCaloHitsPerCluster", m_minCaloHitsPerCluster));
789 
790  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "OverlapWindow", m_xOverlapWindow));
791 
792  PANDORA_RETURN_RESULT_IF_AND_IF(
793  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "DistanceForMatching", m_distanceForMatching));
794 
795  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "PseudoChi2Cut", m_pseudoChi2Cut));
796 
797  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SearchRegion1D", m_searchRegion1D));
798 
799  return STATUS_CODE_SUCCESS;
800 }
801 
802 } // namespace lar_content
void InitializeNearbyClusterMap(const std::string &clusterListName, ClusterToClustersMap &nearbyClusters)
Initialize a nearby cluster map with details relating to a specific cluster list. ...
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
float m_xOverlapWindow
The maximum allowed displacement in x position.
float m_pseudoChi2Cut
Pseudo chi2 cut for three view matching.
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.
Header file for the kd tree linker algo template class.
static bool SortByNHits(const pandora::ParticleFlowObject *const pLhs, const pandora::ParticleFlowObject *const pRhs)
Sort pfos by number of constituent hits.
std::unordered_map< const pandora::CaloHit *, const pandora::Cluster * > HitToClusterMap
Header file for the pfo helper class.
std::unordered_map< const pandora::Cluster *, float > ClusterLengthMap
const pandora::Cluster * GetClusterV() const
Get cluster in V view.
Particle(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2, const pandora::Cluster *const pCluster3, const pandora::ParticleFlowObject *const pPfo)
Constructor.
void GetTrackPfos(const std::string &inputPfoListName, pandora::PfoVector &pfoVector) const
Get a vector of track-like Pfos in the provided input Pfo lists.
ClusterToClustersMap m_nearbyClustersU
The nearby clusters map for the u view.
static void GetClusters(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::ClusterList &clusterList)
Get a list of clusters of a particular hit type from a list of pfos.
void TwoViewMatching(ClusterLengthMap &clusterLengthMap) const
Match clusters using pairs of views.
enum cvn::HType HitType
ClusterToClustersMap m_nearbyClustersV
The nearby clusters map for the v view.
std::string string
Definition: nybbler.cc:12
void CreateParticles(const ParticleList &particleList) const
Build new particle flow objects.
ClusterToClustersMap m_nearbyClustersW
The nearby clusters map for the w view.
unsigned int GetNCaloHits() const
Get number of calo hits.
Box structure used to define 2D field. It&#39;s used in KDTree building step to divide the detector space...
unsigned int m_minCaloHitsPerCluster
The min number of calo hits per candidate cluster.
std::string m_inputClusterListNameV
The input cluster list name for the v view.
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 IsTrack(const pandora::ParticleFlowObject *const pPfo)
Return track flag based on Pfo Particle ID.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
static float GetTwoDLengthSquared(const pandora::ParticleFlowObject *const pPfo)
Calculate length of Pfo using 2D clusters.
Header file for the geometry helper class.
const pandora::Cluster * m_pClusterU
Address of cluster in U view.
void GetAllPfos(const std::string &inputPfoListName, pandora::PfoVector &pfoVector) const
Get a vector of all Pfos in the provided input Pfo lists.
std::string m_parentPfoListName
The parent pfo list name.
std::string m_inputClusterListNameW
The input cluster list name for the w view.
float m_searchRegion1D
Search region, applied to each dimension, for look-up from kd-trees.
void OneViewMatching(ClusterLengthMap &clusterLengthMap) const
Match clusters using single views.
Header file for the cluster helper class.
std::unordered_map< const pandora::ParticleFlowObject *, float > PfoLengthMap
std::void_t< T > n
void ThreeViewMatching(ClusterLengthMap &clusterLengthMap) const
Match clusters using all three views.
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".
void InitializeNearbyClusterMaps()
Initialize nearby cluster maps.
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterToClustersMap
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).
Header file for the delta ray matching algorithm class.
float GetDistanceSquaredToPfo(const pandora::Cluster *const pCluster, const pandora::ParticleFlowObject *const pPfo) const
Get displacementr between cluster and particle flow object.
static int max(int a, int b)
bool AreClustersMatched(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2, const pandora::Cluster *const pCluster3) const
Look at consistency of a combination of clusters.
Detector simulation of raw signals on wires.
void FindBestParentPfo(const pandora::Cluster *const pClusterU, const pandora::Cluster *const pClusterV, const pandora::Cluster *const pClusterW, ClusterLengthMap &clusterLengthMap, PfoLengthMap &pfoLengthMap, const pandora::ParticleFlowObject *&pBestPfo) const
Find best Pfo to associate a UVW triplet.
void AddToDaughterPfo(const pandora::ClusterList &clusterList, const pandora::ParticleFlowObject *const pParentPfo) const
Merge an input cluster list with an existing daughter Pfo.
std::string m_inputClusterListNameU
The input cluster list name for the u view.
float m_distanceForMatching
The maximum allowed distance between tracks and delta rays.
const pandora::Cluster * GetClusterW() const
Get cluster in W view.
void CreateDaughterPfo(const pandora::ClusterList &clusterList, const pandora::ParticleFlowObject *const pParentPfo) const
Create a new Pfo from an input cluster list and set up a parent/daughter relationship.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
float GetLength(const Particle &particle, ClusterLengthMap &clusterLengthMap) const
Get the length (squared) of a candidate particle.
const pandora::ParticleFlowObject * m_pParentPfo
Address of parent Pfo.
void ClearNearbyClusterMaps()
Clear nearby cluster maps.
void SelectParticles(const ParticleList &inputParticles, ClusterLengthMap &clusterLengthMap, ParticleList &outputParticles) const
Resolve any ambiguities between candidate particles.
const pandora::Cluster * m_pClusterV
Address of cluster in V view.
void GetClusters(const std::string &clusterListName, pandora::ClusterVector &clusterVector) const
Get a vector containing all available input clusters in the provided cluster list, storing sliding linear fits in the algorithm cache.
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 GetLengthFromCache(const pandora::Cluster *const pCluster, ClusterLengthMap &clusterLengthMap) const
Reduce number of length (squared) calculations by caching results when they are first obtained...
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
list x
Definition: train.py:276
std::vector< art::Ptr< recob::Cluster > > ClusterVector
const pandora::Cluster * m_pClusterW
Address of cluster in W view.
const pandora::Cluster * GetClusterU() const
Get cluster in U view.
unsigned int GetNViews() const
Get number of views.
KDTreeBox build_2d_kd_search_region(const pandora::CaloHit *const point, const float x_span, const float z_span)
build_2d_kd_search_region
void search(const KDTreeBoxT< DIM > &searchBox, std::vector< KDTreeNodeInfoT< DATA, DIM >> &resRecHitList)
Search in the KDTree for all points that would be contained in the given searchbox The founded points...
QTextStream & endl(QTextStream &s)
std::string m_daughterPfoListName
The daughter pfo list name for new daughter particles.
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.