LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
DeltaRayMatchingAlgorithm.cc
Go to the documentation of this file.
1 
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 
72 void DeltaRayMatchingAlgorithm::InitializeNearbyClusterMap(const std::string &clusterListName, ClusterToClustersMap &nearbyClusters)
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 
108  HitKDNode2DList found;
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
442  float xMin1(-std::numeric_limits<float>::max()), xMax1(+std::numeric_limits<float>::max());
443  float xMin2(-std::numeric_limits<float>::max()), xMax2(+std::numeric_limits<float>::max());
444  float xMin3(-std::numeric_limits<float>::max()), xMax3(+std::numeric_limits<float>::max());
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  const float pitch1{LArGeometryHelper::GetWirePitch(this->GetPandora(), hitType1)};
471  const float pitch2{LArGeometryHelper::GetWirePitch(this->GetPandora(), hitType2)};
472  const float pitch3{LArGeometryHelper::GetWirePitch(this->GetPandora(), hitType3)};
473  const float pitchMax{std::max({pitch1, pitch2, pitch3})};
474 
475  if (hitType1 == hitType2 || hitType2 == hitType3 || hitType3 == hitType1)
476  throw StatusCodeException(STATUS_CODE_FAILURE);
477 
478  const unsigned int nSamplingPoints(1 + static_cast<unsigned int>(xOverlap / xPitch));
479 
480  for (unsigned int n = 0; n < nSamplingPoints; ++n)
481  {
482  const float x(xMin + (xMax - xMin) * (static_cast<float>(n) + 0.5f) / static_cast<float>(nSamplingPoints));
483  const float xmin(x - xPitch);
484  const float xmax(x + xPitch);
485 
486  try
487  {
488  float zMin1(0.f), zMin2(0.f), zMin3(0.f), zMax1(0.f), zMax2(0.f), zMax3(0.f);
489  pCluster1->GetClusterSpanZ(xmin, xmax, zMin1, zMax1);
490  pCluster2->GetClusterSpanZ(xmin, xmax, zMin2, zMax2);
491  pCluster3->GetClusterSpanZ(xmin, xmax, zMin3, zMax3);
492 
493  const float z1(0.5f * (zMin1 + zMax1));
494  const float z2(0.5f * (zMin2 + zMax2));
495  const float z3(0.5f * (zMin3 + zMax3));
496 
497  const float dz1(zMax1 - zMin1);
498  const float dz2(zMax2 - zMin2);
499  const float dz3(zMax3 - zMin3);
500  const float dz4(pitchMax);
501 
502  const float zproj1(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType2, hitType3, z2, z3));
503  const float zproj2(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType3, hitType1, z3, z1));
504  const float zproj3(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType1, hitType2, z1, z2));
505 
506  const float deltaSquared(((z1 - zproj1) * (z1 - zproj1) + (z2 - zproj2) * (z2 - zproj2) + (z3 - zproj3) * (z3 - zproj3)) / 3.f);
507  const float sigmaSquared(dz1 * dz1 + dz2 * dz2 + dz3 * dz3 + dz4 * dz4);
508  const float pseudoChi2(deltaSquared / sigmaSquared);
509 
510  if (pseudoChi2 < m_pseudoChi2Cut)
511  return true;
512  }
513  catch (StatusCodeException &statusCodeException)
514  {
515  if (STATUS_CODE_NOT_FOUND != statusCodeException.GetStatusCode())
516  throw statusCodeException;
517  }
518  }
519 
520  return false;
521 }
522 
523 //------------------------------------------------------------------------------------------------------------------------------------------
524 
525 void DeltaRayMatchingAlgorithm::FindBestParentPfo(const Cluster *const pCluster1, const Cluster *const pCluster2,
526  const Cluster *const pCluster3, ClusterLengthMap &clusterLengthMap, PfoLengthMap &pfoLengthMap, const ParticleFlowObject *&pBestPfo) const
527 {
528  PfoVector pfoVector;
529  this->GetTrackPfos(m_parentPfoListName, pfoVector);
530  this->GetAllPfos(m_daughterPfoListName, pfoVector);
531 
532  if (pfoVector.empty())
533  throw StatusCodeException(STATUS_CODE_FAILURE);
534 
535  unsigned int numViews(0);
536  float lengthSquared(0.f);
537 
538  if (pCluster1)
539  {
540  lengthSquared += this->GetLengthFromCache(pCluster1, clusterLengthMap);
541  ++numViews;
542  }
543 
544  if (pCluster2)
545  {
546  lengthSquared += this->GetLengthFromCache(pCluster2, clusterLengthMap);
547  ++numViews;
548  }
549 
550  if (pCluster3)
551  {
552  lengthSquared += this->GetLengthFromCache(pCluster3, clusterLengthMap);
553  ++numViews;
554  }
555 
556  float bestDistanceSquared(static_cast<float>(numViews) * m_distanceForMatching * m_distanceForMatching);
557 
558  for (const ParticleFlowObject *const pPfo : pfoVector)
559  {
560  if (lengthSquared > this->GetLengthFromCache(pPfo, pfoLengthMap))
561  continue;
562 
563  try
564  {
565  float distanceSquared(0.f);
566 
567  if (NULL != pCluster1)
568  distanceSquared += this->GetDistanceSquaredToPfo(pCluster1, pPfo);
569 
570  if (NULL != pCluster2)
571  distanceSquared += this->GetDistanceSquaredToPfo(pCluster2, pPfo);
572 
573  if (NULL != pCluster3)
574  distanceSquared += this->GetDistanceSquaredToPfo(pCluster3, pPfo);
575 
576  if (distanceSquared < bestDistanceSquared)
577  {
578  pBestPfo = pPfo;
579  bestDistanceSquared = distanceSquared;
580  }
581  }
582  catch (StatusCodeException &statusCodeException)
583  {
584  if (!(STATUS_CODE_NOT_FOUND == statusCodeException.GetStatusCode()))
585  throw statusCodeException;
586  }
587  }
588 }
589 
590 //------------------------------------------------------------------------------------------------------------------------------------------
591 
592 float DeltaRayMatchingAlgorithm::GetLengthFromCache(const Cluster *const pCluster, ClusterLengthMap &clusterLengthMap) const
593 {
594  ClusterLengthMap::const_iterator iter = clusterLengthMap.find(pCluster);
595 
596  if (clusterLengthMap.end() != iter)
597  return iter->second;
598 
599  const float lengthSquared(LArClusterHelper::GetLengthSquared(pCluster));
600  (void)clusterLengthMap.insert(ClusterLengthMap::value_type(pCluster, lengthSquared));
601  return lengthSquared;
602 }
603 
604 //------------------------------------------------------------------------------------------------------------------------------------------
605 
606 float DeltaRayMatchingAlgorithm::GetLengthFromCache(const ParticleFlowObject *const pPfo, PfoLengthMap &pfoLengthMap) const
607 {
608  PfoLengthMap::const_iterator iter = pfoLengthMap.find(pPfo);
609 
610  if (pfoLengthMap.end() != iter)
611  return iter->second;
612 
613  const float lengthSquared(LArPfoHelper::GetTwoDLengthSquared(pPfo));
614  (void)pfoLengthMap.insert(PfoLengthMap::value_type(pPfo, lengthSquared));
615  return lengthSquared;
616 }
617 
618 //------------------------------------------------------------------------------------------------------------------------------------------
619 
620 float DeltaRayMatchingAlgorithm::GetLength(const Particle &particle, ClusterLengthMap &clusterLengthMap) const
621 {
622  float lengthSquared(0.f);
623 
624  if (particle.GetClusterU())
625  lengthSquared += this->GetLengthFromCache(particle.GetClusterU(), clusterLengthMap);
626 
627  if (particle.GetClusterV())
628  lengthSquared += this->GetLengthFromCache(particle.GetClusterV(), clusterLengthMap);
629 
630  if (particle.GetClusterW())
631  lengthSquared += this->GetLengthFromCache(particle.GetClusterW(), clusterLengthMap);
632 
633  return lengthSquared;
634 }
635 
636 //------------------------------------------------------------------------------------------------------------------------------------------
637 
638 float DeltaRayMatchingAlgorithm::GetDistanceSquaredToPfo(const Cluster *const pCluster, const ParticleFlowObject *const pPfo) const
639 {
640  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster));
641 
642  if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
643  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
644 
645  ClusterList comparisonList;
646  const ClusterToClustersMap &nearbyClusters((TPC_VIEW_U == hitType) ? m_nearbyClustersU
647  : (TPC_VIEW_V == hitType) ? m_nearbyClustersV
649 
650  if (!nearbyClusters.count(pCluster))
651  return std::numeric_limits<float>::max();
652 
653  ClusterList pfoClusterList;
654  LArPfoHelper::GetClusters(pPfo, hitType, pfoClusterList);
655 
656  for (const Cluster *const pPfoCluster : pfoClusterList)
657  {
658  const ClusterList &clusterList(nearbyClusters.at(pCluster));
659 
660  if ((clusterList.end() != std::find(clusterList.begin(), clusterList.end(), pPfoCluster)) &&
661  (comparisonList.end() == std::find(comparisonList.begin(), comparisonList.end(), pPfoCluster)))
662  {
663  comparisonList.push_back(pPfoCluster);
664  }
665  }
666 
667  if (comparisonList.empty())
668  return std::numeric_limits<float>::max();
669 
670  return LArClusterHelper::GetClosestDistance(pCluster, comparisonList);
671 }
672 
673 //------------------------------------------------------------------------------------------------------------------------------------------
674 
675 void DeltaRayMatchingAlgorithm::CreateDaughterPfo(const ClusterList &clusterList, const ParticleFlowObject *const pParentPfo) const
676 {
677  const PfoList *pPfoList = NULL;
678  std::string pfoListName;
679  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pPfoList, pfoListName));
680 
681  // TODO Correct these placeholder parameters
682  PandoraContentApi::ParticleFlowObject::Parameters pfoParameters;
683  pfoParameters.m_particleId = E_MINUS; // SHOWER
684  pfoParameters.m_charge = PdgTable::GetParticleCharge(pfoParameters.m_particleId.Get());
685  pfoParameters.m_mass = PdgTable::GetParticleMass(pfoParameters.m_particleId.Get());
686  pfoParameters.m_energy = 0.f;
687  pfoParameters.m_momentum = CartesianVector(0.f, 0.f, 0.f);
688  pfoParameters.m_clusterList = clusterList;
689 
690  const ParticleFlowObject *pDaughterPfo(NULL);
691  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::Create(*this, pfoParameters, pDaughterPfo));
692 
693  if (!pPfoList->empty())
694  {
695  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Pfo>(*this, m_daughterPfoListName));
696  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SetPfoParentDaughterRelationship(*this, pParentPfo, pDaughterPfo));
697  }
698 }
699 
700 //------------------------------------------------------------------------------------------------------------------------------------------
701 
702 void DeltaRayMatchingAlgorithm::AddToDaughterPfo(const ClusterList &clusterList, const ParticleFlowObject *const pParentPfo) const
703 {
704  for (const Cluster *const pDaughterCluster : clusterList)
705  {
706  const HitType hitType(LArClusterHelper::GetClusterHitType(pDaughterCluster));
707  const std::string clusterListName((TPC_VIEW_U == hitType) ? m_inputClusterListNameU
708  : (TPC_VIEW_V == hitType) ? m_inputClusterListNameV
710 
711  ClusterList pfoClusters;
712  LArPfoHelper::GetClusters(pParentPfo, hitType, pfoClusters);
713 
714  if (pfoClusters.empty())
715  throw StatusCodeException(STATUS_CODE_FAILURE);
716 
717  const Cluster *const pParentCluster = *(pfoClusters.begin());
718 
719  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=,
720  PandoraContentApi::MergeAndDeleteClusters(*this, pParentCluster, pDaughterCluster, clusterListName, clusterListName));
721  }
722 }
723 
724 //------------------------------------------------------------------------------------------------------------------------------------------
725 //------------------------------------------------------------------------------------------------------------------------------------------
726 
728  const Cluster *const pCluster1, const Cluster *const pCluster2, const Cluster *const pCluster3, const ParticleFlowObject *const pPfo) :
729  m_pClusterU(NULL),
730  m_pClusterV(NULL),
731  m_pClusterW(NULL),
732  m_pParentPfo(NULL)
733 {
734  const HitType hitType1(NULL != pCluster1 ? LArClusterHelper::GetClusterHitType(pCluster1) : HIT_CUSTOM);
735  const HitType hitType2(NULL != pCluster2 ? LArClusterHelper::GetClusterHitType(pCluster2) : HIT_CUSTOM);
736  const HitType hitType3(NULL != pCluster3 ? LArClusterHelper::GetClusterHitType(pCluster3) : HIT_CUSTOM);
737 
738  m_pClusterU = ((TPC_VIEW_U == hitType1) ? pCluster1
739  : (TPC_VIEW_U == hitType2) ? pCluster2
740  : (TPC_VIEW_U == hitType3) ? pCluster3
741  : NULL);
742  m_pClusterV = ((TPC_VIEW_V == hitType1) ? pCluster1
743  : (TPC_VIEW_V == hitType2) ? pCluster2
744  : (TPC_VIEW_V == hitType3) ? pCluster3
745  : NULL);
746  m_pClusterW = ((TPC_VIEW_W == hitType1) ? pCluster1
747  : (TPC_VIEW_W == hitType2) ? pCluster2
748  : (TPC_VIEW_W == hitType3) ? pCluster3
749  : NULL);
750  m_pParentPfo = pPfo;
751 
752  if (NULL == m_pClusterU && NULL == m_pClusterV && NULL == m_pClusterW)
753  throw StatusCodeException(STATUS_CODE_FAILURE);
754 }
755 
756 //------------------------------------------------------------------------------------------------------------------------------------------
757 
759 {
760  unsigned int numViews(0);
761 
762  if (NULL != m_pClusterU)
763  numViews += 1;
764 
765  if (NULL != m_pClusterV)
766  numViews += 1;
767 
768  if (NULL != m_pClusterW)
769  numViews += 1;
770 
771  return numViews;
772 }
773 
774 //------------------------------------------------------------------------------------------------------------------------------------------
775 
777 {
778  unsigned int numCaloHits(0);
779 
780  if (NULL != m_pClusterU)
781  numCaloHits += m_pClusterU->GetNCaloHits();
782 
783  if (NULL != m_pClusterV)
784  numCaloHits += m_pClusterV->GetNCaloHits();
785 
786  if (NULL != m_pClusterW)
787  numCaloHits += m_pClusterW->GetNCaloHits();
788 
789  return numCaloHits;
790 }
791 
792 //------------------------------------------------------------------------------------------------------------------------------------------
793 //------------------------------------------------------------------------------------------------------------------------------------------
794 
795 StatusCode DeltaRayMatchingAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
796 {
797  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "ParentPfoListName", m_parentPfoListName));
798  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "DaughterPfoListName", m_daughterPfoListName));
799  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameU", m_inputClusterListNameU));
800  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameV", m_inputClusterListNameV));
801  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameW", m_inputClusterListNameW));
802 
803  PANDORA_RETURN_RESULT_IF_AND_IF(
804  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinCaloHitsPerCluster", m_minCaloHitsPerCluster));
805 
806  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "OverlapWindow", m_xOverlapWindow));
807 
808  PANDORA_RETURN_RESULT_IF_AND_IF(
809  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "DistanceForMatching", m_distanceForMatching));
810 
811  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "PseudoChi2Cut", m_pseudoChi2Cut));
812 
813  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SearchRegion1D", m_searchRegion1D));
814 
815  return STATUS_CODE_SUCCESS;
816 }
817 
818 } // namespace lar_content
Float_t x
Definition: compare.C:6
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.
ClusterToClustersMap m_nearbyClustersV
The nearby clusters map for the v view.
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 GetTwoDLengthSquared(const pandora::ParticleFlowObject *const pPfo)
Calculate length of Pfo using 2D clusters.
TFile f
Definition: plotHisto.C:6
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
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).
static float GetWirePitch(const pandora::Pandora &pandora, const pandora::HitType view, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
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.
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.
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.
HitType
Definition: HitType.h:12
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.
Char_t n[5]
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...
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.