LArSoft  v06_85_00
Liquid Argon Software toolkit - http://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,
76  clusterListName, pClusterList))
77 
78  if ((NULL == pClusterList) || pClusterList->empty())
79  return;
80 
81  HitToClusterMap hitToClusterMap;
82  CaloHitList allCaloHits;
83 
84  for (const Cluster *const pCluster : *pClusterList)
85  {
86  CaloHitList daughterHits;
87  pCluster->GetOrderedCaloHitList().FillCaloHitList(daughterHits);
88  allCaloHits.insert(allCaloHits.end(), daughterHits.begin(), daughterHits.end());
89 
90  for (const CaloHit *const pCaloHit : daughterHits)
91  (void) hitToClusterMap.insert(HitToClusterMap::value_type(pCaloHit, pCluster));
92  }
93 
94  HitKDTree2D kdTree;
95  HitKDNode2DList hitKDNode2DList;
96 
97  KDTreeBox hitsBoundingRegion2D(fill_and_bound_2d_kd_tree(allCaloHits, hitKDNode2DList));
98  kdTree.build(hitKDNode2DList, hitsBoundingRegion2D);
99 
100  for (const Cluster *const pCluster : *pClusterList)
101  {
102  CaloHitList daughterHits;
103  pCluster->GetOrderedCaloHitList().FillCaloHitList(daughterHits);
104 
105  for (const CaloHit *const pCaloHit : daughterHits)
106  {
108 
109  HitKDNode2DList found;
110  kdTree.search(searchRegionHits, found);
111 
112  for (const auto &hit : found)
113  {
114  ClusterList &nearbyClusterList(nearbyClusters[pCluster]);
115  const Cluster *const pNearbyCluster(hitToClusterMap.at(hit.data));
116 
117  if (nearbyClusterList.end() == std::find(nearbyClusterList.begin(), nearbyClusterList.end(), pNearbyCluster))
118  nearbyClusterList.push_back(pNearbyCluster);
119  }
120  }
121  }
122 }
123 
124 //------------------------------------------------------------------------------------------------------------------------------------------
125 
127 {
128  m_nearbyClustersU.clear();
129  m_nearbyClustersV.clear();
130  m_nearbyClustersW.clear();
131 }
132 
133 //------------------------------------------------------------------------------------------------------------------------------------------
134 
135 void DeltaRayMatchingAlgorithm::GetAllPfos(const std::string &inputPfoListName, PfoVector &pfoVector) const
136 {
137  const PfoList *pPfoList = NULL;
138  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this,
139  inputPfoListName, pPfoList));
140 
141  if (NULL == pPfoList)
142  return;
143 
144  for (PfoList::const_iterator iter = pPfoList->begin(), iterEnd = pPfoList->end(); iter != iterEnd; ++iter)
145  pfoVector.push_back(*iter);
146 
147  std::sort(pfoVector.begin(), pfoVector.end(), LArPfoHelper::SortByNHits);
148 }
149 
150 //------------------------------------------------------------------------------------------------------------------------------------------
151 
152 void DeltaRayMatchingAlgorithm::GetTrackPfos(const std::string &inputPfoListName, PfoVector &pfoVector) const
153 {
154  PfoVector inputVector;
155  this->GetAllPfos(inputPfoListName, inputVector);
156 
157  for (PfoVector::const_iterator iter = inputVector.begin(), iterEnd = inputVector.end(); iter != iterEnd; ++iter)
158  {
159  const ParticleFlowObject *const pPfo = *iter;
160 
161  if (!LArPfoHelper::IsTrack(pPfo))
162  continue;
163 
164  pfoVector.push_back(pPfo);
165  }
166 
167  // ATTN Track pfo list is sorted only because the inputVector is sorted
168 }
169 
170 //------------------------------------------------------------------------------------------------------------------------------------------
171 
172 void DeltaRayMatchingAlgorithm::GetClusters(const std::string &inputClusterListName, pandora::ClusterVector &clusterVector) const
173 {
174  const ClusterList *pClusterList = NULL;
175  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this,
176  inputClusterListName, pClusterList))
177 
178  if (NULL == pClusterList)
179  return;
180 
181  for (ClusterList::const_iterator cIter = pClusterList->begin(), cIterEnd = pClusterList->end(); cIter != cIterEnd; ++cIter)
182  {
183  const Cluster *const pCluster = *cIter;
184 
185  if (!pCluster->IsAvailable() || (pCluster->GetNCaloHits() < m_minCaloHitsPerCluster))
186  continue;
187 
188  clusterVector.push_back(pCluster);
189  }
190 
191  std::sort(clusterVector.begin(), clusterVector.end(), LArClusterHelper::SortByNHits);
192 }
193 
194 //------------------------------------------------------------------------------------------------------------------------------------------
195 
197 {
198  ClusterVector clustersU, clustersV, clustersW;
199  this->GetClusters(m_inputClusterListNameU, clustersU);
200  this->GetClusters(m_inputClusterListNameV, clustersV);
201  this->GetClusters(m_inputClusterListNameW, clustersW);
202 
203  PfoLengthMap pfoLengthMap;
204  ParticleList initialParticleList, finalParticleList;
205  this->ThreeViewMatching(clustersU, clustersV, clustersW, clusterLengthMap, pfoLengthMap, initialParticleList);
206  this->SelectParticles(initialParticleList, clusterLengthMap, finalParticleList);
207  this->CreateParticles(finalParticleList);
208 }
209 
210 //------------------------------------------------------------------------------------------------------------------------------------------
211 
213 {
214  ClusterVector clustersU, clustersV, clustersW;
215  this->GetClusters(m_inputClusterListNameU, clustersU);
216  this->GetClusters(m_inputClusterListNameV, clustersV);
217  this->GetClusters(m_inputClusterListNameW, clustersW);
218 
219  PfoLengthMap pfoLengthMap;
220  ParticleList initialParticleList, finalParticleList;
221  this->TwoViewMatching(clustersU, clustersV, clusterLengthMap, pfoLengthMap, initialParticleList);
222  this->TwoViewMatching(clustersV, clustersW, clusterLengthMap, pfoLengthMap, initialParticleList);
223  this->TwoViewMatching(clustersW, clustersU, clusterLengthMap, pfoLengthMap, initialParticleList);
224  this->SelectParticles(initialParticleList, clusterLengthMap, finalParticleList);
225  this->CreateParticles(finalParticleList);
226 }
227 
228 //------------------------------------------------------------------------------------------------------------------------------------------
229 
231 {
232  ClusterVector clustersU, clustersV, clustersW;
233  this->GetClusters(m_inputClusterListNameU, clustersU);
234  this->GetClusters(m_inputClusterListNameV, clustersV);
235  this->GetClusters(m_inputClusterListNameW, clustersW);
236 
237  PfoLengthMap pfoLengthMap;
238  ParticleList initialParticleList, finalParticleList;
239  this->ThreeViewMatching(clustersU, clustersV, clustersW, clusterLengthMap, pfoLengthMap, initialParticleList);
240  this->OneViewMatching(clustersU, clusterLengthMap, pfoLengthMap, initialParticleList);
241  this->OneViewMatching(clustersV, clusterLengthMap, pfoLengthMap, initialParticleList);
242  this->OneViewMatching(clustersW, clusterLengthMap, pfoLengthMap, initialParticleList);
243  this->SelectParticles(initialParticleList, clusterLengthMap, finalParticleList);
244  this->CreateParticles(finalParticleList);
245 }
246 
247 //------------------------------------------------------------------------------------------------------------------------------------------
248 
249 void DeltaRayMatchingAlgorithm::ThreeViewMatching(const ClusterVector &clusters1, const ClusterVector &clusters2, const ClusterVector &clusters3,
250  ClusterLengthMap &clusterLengthMap, PfoLengthMap &pfoLengthMap, ParticleList &particleList) const
251 {
252  if (clusters1.empty() || clusters2.empty() || clusters3.empty())
253  return;
254 
255  for (const Cluster *const pCluster1 : clusters1)
256  {
257  if (!pCluster1->IsAvailable())
258  continue;
259 
260  for (const Cluster *const pCluster2 : clusters2)
261  {
262  if (!pCluster2->IsAvailable())
263  continue;
264 
265  for (const Cluster *const pCluster3 : clusters3)
266  {
267  if (!pCluster3->IsAvailable())
268  continue;
269 
270  if (!this->AreClustersMatched(pCluster1, pCluster2, pCluster3))
271  continue;
272 
273  const ParticleFlowObject *pBestPfo = NULL;
274  this->FindBestParentPfo(pCluster1, pCluster2, pCluster3, clusterLengthMap, pfoLengthMap, pBestPfo);
275 
276  // ATTN Need to record all matches when all three views are used
277  particleList.push_back(Particle(pCluster1, pCluster2, pCluster3, pBestPfo));
278  }
279  }
280  }
281 }
282 
283 //------------------------------------------------------------------------------------------------------------------------------------------
284 
285 void DeltaRayMatchingAlgorithm::TwoViewMatching(const ClusterVector &clusters1, const ClusterVector &clusters2, ClusterLengthMap &clusterLengthMap,
286  PfoLengthMap &pfoLengthMap, ParticleList &particleList) const
287 {
288  if (clusters1.empty() || clusters2.empty())
289  return;
290 
291  for (const Cluster *const pCluster1 : clusters1)
292  {
293  if (!pCluster1->IsAvailable())
294  continue;
295 
296  for (const Cluster *const pCluster2 : clusters2)
297  {
298  if (!pCluster2->IsAvailable())
299  continue;
300 
301  if (!this->AreClustersMatched(pCluster1, pCluster2, NULL))
302  continue;
303 
304  const ParticleFlowObject *pBestPfo = NULL;
305  this->FindBestParentPfo(pCluster1, pCluster2, NULL, clusterLengthMap, pfoLengthMap, pBestPfo);
306 
307  if (NULL == pBestPfo)
308  continue;
309 
310  particleList.push_back(Particle(pCluster1, pCluster2, NULL, pBestPfo));
311  }
312  }
313 }
314 
315 //------------------------------------------------------------------------------------------------------------------------------------------
316 
317 void DeltaRayMatchingAlgorithm::OneViewMatching(const ClusterVector &clusters, ClusterLengthMap &clusterLengthMap, PfoLengthMap &pfoLengthMap,
318  ParticleList &particleList) const
319 {
320  if (clusters.empty())
321  return;
322 
323  for (const Cluster *const pCluster : clusters)
324  {
325  if (!pCluster->IsAvailable())
326  continue;
327 
328  const ParticleFlowObject *pBestPfo = NULL;
329  this->FindBestParentPfo(pCluster, NULL, NULL, clusterLengthMap, pfoLengthMap, pBestPfo);
330 
331  if (NULL == pBestPfo)
332  continue;
333 
334  particleList.push_back(Particle(pCluster, NULL, NULL, pBestPfo));
335  }
336 }
337 
338 //------------------------------------------------------------------------------------------------------------------------------------------
339 
340 void DeltaRayMatchingAlgorithm::SelectParticles(const ParticleList &initialParticles, ClusterLengthMap &clusterLengthMap, ParticleList &finalParticles) const
341 {
342  for (const Particle &particle1 : initialParticles)
343  {
344  bool isGoodParticle(true);
345 
346  for (const Particle &particle2 : initialParticles)
347  {
348  const bool commonU(particle1.GetClusterU() == particle2.GetClusterU());
349  const bool commonV(particle1.GetClusterV() == particle2.GetClusterV());
350  const bool commonW(particle1.GetClusterW() == particle2.GetClusterW());
351 
352  const bool ambiguousU(commonU && NULL != particle1.GetClusterU());
353  const bool ambiguousV(commonV && NULL != particle1.GetClusterV());
354  const bool ambiguousW(commonW && NULL != particle1.GetClusterW());
355 
356  if (commonU && commonV && commonW)
357  continue;
358 
359  if (ambiguousU || ambiguousV || ambiguousW)
360  {
361  if (particle2.GetNViews() > particle1.GetNViews())
362  {
363  isGoodParticle = false;
364  }
365  else if (particle2.GetNViews() == particle1.GetNViews() && NULL != particle2.GetParentPfo())
366  {
367  if ((NULL == particle1.GetParentPfo()) || (particle2.GetNCaloHits() > particle1.GetNCaloHits()) ||
368  (particle2.GetNCaloHits() == particle1.GetNCaloHits() && this->GetLength(particle2, clusterLengthMap) >= this->GetLength(particle1, clusterLengthMap)) )
369  {
370  isGoodParticle = false;
371  }
372  }
373 
374  if (!isGoodParticle)
375  break;
376  }
377  }
378 
379  if (isGoodParticle && NULL != particle1.GetParentPfo())
380  finalParticles.push_back(particle1);
381  }
382 }
383 
384 //------------------------------------------------------------------------------------------------------------------------------------------
385 
387 {
388  PfoVector parentVector, daughterVector;
389  this->GetTrackPfos(m_parentPfoListName, parentVector);
390  this->GetAllPfos(m_daughterPfoListName, daughterVector);
391 
392  PfoList parentList(parentVector.begin(), parentVector.end());
393  PfoList daughterList(daughterVector.begin(), daughterVector.end());
394 
395  for (const Particle &particle : particleList)
396  {
397  const ParticleFlowObject *const pParentPfo = particle.GetParentPfo();
398 
399  if (NULL == pParentPfo)
400  continue;
401 
402  const Cluster *const pClusterU = particle.GetClusterU();
403  const Cluster *const pClusterV = particle.GetClusterV();
404  const Cluster *const pClusterW = particle.GetClusterW();
405 
406  if (NULL == pClusterU && NULL == pClusterV && NULL == pClusterW)
407  throw StatusCodeException(STATUS_CODE_FAILURE);
408 
409  ClusterList clusterList;
410 
411  if (pClusterU)
412  clusterList.push_back(pClusterU);
413 
414  if (pClusterV)
415  clusterList.push_back(pClusterV);
416 
417  if (pClusterW)
418  clusterList.push_back(pClusterW);
419 
420  if (parentList.end() != std::find(parentList.begin(), parentList.end(), pParentPfo))
421  {
422  this->CreateDaughterPfo(clusterList, pParentPfo);
423  }
424  else if (daughterList.end() != std::find(daughterList.begin(), daughterList.end(), pParentPfo))
425  {
426  this->AddToDaughterPfo(clusterList, pParentPfo);
427  }
428  else
429  {
430  throw StatusCodeException(STATUS_CODE_FAILURE);
431  }
432  }
433 }
434 
435 //------------------------------------------------------------------------------------------------------------------------------------------
436 
437 bool DeltaRayMatchingAlgorithm::AreClustersMatched(const Cluster *const pCluster1, const Cluster *const pCluster2,
438  const Cluster *const pCluster3) const
439 {
440  if (NULL == pCluster1 && NULL == pCluster2 && NULL == pCluster3)
441  throw StatusCodeException(STATUS_CODE_FAILURE);
442 
443  // First step: Check X overlap
447 
448  if (NULL != pCluster1)
449  LArClusterHelper::GetClusterSpanX(pCluster1, xMin1, xMax1);
450 
451  if (NULL != pCluster2)
452  LArClusterHelper::GetClusterSpanX(pCluster2, xMin2, xMax2);
453 
454  if (NULL != pCluster3)
455  LArClusterHelper::GetClusterSpanX(pCluster3, xMin3, xMax3);
456 
457  const float xPitch(0.5 * m_xOverlapWindow);
458  const float xMin(std::max(xMin1, std::max(xMin2, xMin3)) - xPitch);
459  const float xMax(std::min(xMax1, std::min(xMax2, xMax3)) + xPitch);
460  const float xOverlap(xMax - xMin);
461 
462  if (xOverlap < std::numeric_limits<float>::epsilon())
463  return false;
464 
465  if (NULL == pCluster1 || NULL == pCluster2 || NULL == pCluster3)
466  return true;
467 
468  // Second step: Check 3D matching
469  const HitType hitType1(LArClusterHelper::GetClusterHitType(pCluster1));
470  const HitType hitType2(LArClusterHelper::GetClusterHitType(pCluster2));
471  const HitType hitType3(LArClusterHelper::GetClusterHitType(pCluster3));
472 
473  if (hitType1 == hitType2 || hitType2 == hitType3 || hitType3 == hitType1)
474  throw StatusCodeException(STATUS_CODE_FAILURE);
475 
476  const unsigned int nSamplingPoints(1 + static_cast<unsigned int>(xOverlap / xPitch));
477 
478  for (unsigned int n = 0; n < nSamplingPoints; ++n)
479  {
480  const float x(xMin + (xMax - xMin) * (static_cast<float>(n) + 0.5f) / static_cast<float>(nSamplingPoints));
481  const float xmin(x - xPitch);
482  const float xmax(x + xPitch);
483 
484  try
485  {
486  float zMin1(0.f), zMin2(0.f), zMin3(0.f), zMax1(0.f), zMax2(0.f), zMax3(0.f);
487  LArClusterHelper::GetClusterSpanZ(pCluster1, xmin, xmax, zMin1, zMax1);
488  LArClusterHelper::GetClusterSpanZ(pCluster2, xmin, xmax, zMin2, zMax2);
489  LArClusterHelper::GetClusterSpanZ(pCluster3, xmin, xmax, zMin3, zMax3);
490 
491  const float z1(0.5f * (zMin1 + zMax1));
492  const float z2(0.5f * (zMin2 + zMax2));
493  const float z3(0.5f * (zMin3 + zMax3));
494 
495  const float dz1(zMax1 - zMin1);
496  const float dz2(zMax2 - zMin2);
497  const float dz3(zMax3 - zMin3);
498  const float dz4(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
499 
500  const float zproj1(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType2, hitType3, z2, z3));
501  const float zproj2(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType3, hitType1, z3, z1));
502  const float zproj3(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType1, hitType2, z1, z2));
503 
504  const float deltaSquared(((z1 - zproj1) * (z1 - zproj1) + (z2 - zproj2) * (z2 - zproj2) + (z3 - zproj3) * (z3 - zproj3)) / 3.f);
505  const float sigmaSquared(dz1 * dz1 + dz2 * dz2 + dz3 * dz3 + dz4 * dz4);
506  const float pseudoChi2(deltaSquared / sigmaSquared);
507 
508  if (pseudoChi2 < m_pseudoChi2Cut)
509  return true;
510  }
511  catch(StatusCodeException &statusCodeException)
512  {
513  if (STATUS_CODE_NOT_FOUND != statusCodeException.GetStatusCode())
514  throw statusCodeException;
515  }
516  }
517 
518  return false;
519 }
520 
521 //------------------------------------------------------------------------------------------------------------------------------------------
522 
523 void DeltaRayMatchingAlgorithm::FindBestParentPfo(const Cluster *const pCluster1, const Cluster *const pCluster2, const Cluster *const pCluster3,
524  ClusterLengthMap &clusterLengthMap, PfoLengthMap &pfoLengthMap, const ParticleFlowObject *&pBestPfo) const
525 {
526  PfoVector pfoVector;
527  this->GetTrackPfos(m_parentPfoListName, pfoVector);
528  this->GetAllPfos(m_daughterPfoListName, pfoVector);
529 
530  if (pfoVector.empty())
531  throw StatusCodeException(STATUS_CODE_FAILURE);
532 
533  unsigned int numViews(0);
534  float lengthSquared(0.f);
535 
536  if (pCluster1)
537  {
538  lengthSquared += this->GetLengthFromCache(pCluster1, clusterLengthMap);
539  ++numViews;
540  }
541 
542  if (pCluster2)
543  {
544  lengthSquared += this->GetLengthFromCache(pCluster2, clusterLengthMap);
545  ++numViews;
546  }
547 
548  if (pCluster3)
549  {
550  lengthSquared += this->GetLengthFromCache(pCluster3, clusterLengthMap);
551  ++numViews;
552  }
553 
554  float bestDistanceSquared(static_cast<float>(numViews) * m_distanceForMatching * m_distanceForMatching);
555 
556  for (const ParticleFlowObject *const pPfo : pfoVector)
557  {
558  if (lengthSquared > this->GetLengthFromCache(pPfo, pfoLengthMap))
559  continue;
560 
561  try
562  {
563  float distanceSquared(0.f);
564 
565  if (NULL != pCluster1)
566  distanceSquared += this->GetDistanceSquaredToPfo(pCluster1, pPfo);
567 
568  if (NULL != pCluster2)
569  distanceSquared += this->GetDistanceSquaredToPfo(pCluster2, pPfo);
570 
571  if (NULL != pCluster3)
572  distanceSquared += this->GetDistanceSquaredToPfo(pCluster3, pPfo);
573 
574  if (distanceSquared < bestDistanceSquared)
575  {
576  pBestPfo = pPfo;
577  bestDistanceSquared = distanceSquared;
578  }
579  }
580  catch (StatusCodeException &statusCodeException)
581  {
582  if (!(STATUS_CODE_NOT_FOUND == statusCodeException.GetStatusCode()))
583  throw statusCodeException;
584  }
585  }
586 }
587 
588 //------------------------------------------------------------------------------------------------------------------------------------------
589 
590 float DeltaRayMatchingAlgorithm::GetLengthFromCache(const Cluster *const pCluster, ClusterLengthMap &clusterLengthMap) const
591 {
592  ClusterLengthMap::const_iterator iter = clusterLengthMap.find(pCluster);
593 
594  if (clusterLengthMap.end() != iter)
595  return iter->second;
596 
597  const float lengthSquared(LArClusterHelper::GetLengthSquared(pCluster));
598  (void) clusterLengthMap.insert(ClusterLengthMap::value_type(pCluster, lengthSquared));
599  return lengthSquared;
600 }
601 
602 //------------------------------------------------------------------------------------------------------------------------------------------
603 
604 float DeltaRayMatchingAlgorithm::GetLengthFromCache(const ParticleFlowObject *const pPfo, PfoLengthMap &pfoLengthMap) const
605 {
606  PfoLengthMap::const_iterator iter = pfoLengthMap.find(pPfo);
607 
608  if (pfoLengthMap.end() != iter)
609  return iter->second;
610 
611  const float lengthSquared(LArPfoHelper::GetTwoDLengthSquared(pPfo));
612  (void) pfoLengthMap.insert(PfoLengthMap::value_type(pPfo, lengthSquared));
613  return lengthSquared;
614 }
615 
616 //------------------------------------------------------------------------------------------------------------------------------------------
617 
618 float DeltaRayMatchingAlgorithm::GetLength(const Particle &particle, ClusterLengthMap &clusterLengthMap) const
619 {
620  float lengthSquared(0.f);
621 
622  if (particle.GetClusterU())
623  lengthSquared += this->GetLengthFromCache(particle.GetClusterU(), clusterLengthMap);
624 
625  if (particle.GetClusterV())
626  lengthSquared += this->GetLengthFromCache(particle.GetClusterV(), clusterLengthMap);
627 
628  if (particle.GetClusterW())
629  lengthSquared += this->GetLengthFromCache(particle.GetClusterW(), clusterLengthMap);
630 
631  return lengthSquared;
632 }
633 
634 //------------------------------------------------------------------------------------------------------------------------------------------
635 
636 float DeltaRayMatchingAlgorithm::GetDistanceSquaredToPfo(const Cluster *const pCluster, const ParticleFlowObject *const pPfo) const
637 {
638  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster));
639 
640  if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
641  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
642 
643  ClusterList comparisonList;
644  const ClusterToClustersMap &nearbyClusters((TPC_VIEW_U == hitType) ? m_nearbyClustersU : (TPC_VIEW_V == hitType) ? m_nearbyClustersV : m_nearbyClustersW);
645 
646  if (!nearbyClusters.count(pCluster))
648 
649  ClusterList pfoClusterList;
650  LArPfoHelper::GetClusters(pPfo, hitType, pfoClusterList);
651 
652  for (const Cluster *const pPfoCluster : pfoClusterList)
653  {
654  const ClusterList &clusterList(nearbyClusters.at(pCluster));
655 
656  if ((clusterList.end() != std::find(clusterList.begin(), clusterList.end(), pPfoCluster)) &&
657  (comparisonList.end() == std::find(comparisonList.begin(), comparisonList.end(), pPfoCluster)))
658  {
659  comparisonList.push_back(pPfoCluster);
660  }
661  }
662 
663  if (comparisonList.empty())
665 
666  return LArClusterHelper::GetClosestDistance(pCluster, comparisonList);
667 }
668 
669 //------------------------------------------------------------------------------------------------------------------------------------------
670 
671 void DeltaRayMatchingAlgorithm::CreateDaughterPfo(const ClusterList &clusterList, const ParticleFlowObject *const pParentPfo) const
672 {
673  const PfoList *pPfoList = NULL; std::string pfoListName;
674  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pPfoList, pfoListName));
675 
676  // TODO Correct these placeholder parameters
677  PandoraContentApi::ParticleFlowObject::Parameters pfoParameters;
678  pfoParameters.m_particleId = E_MINUS; // SHOWER
679  pfoParameters.m_charge = PdgTable::GetParticleCharge(pfoParameters.m_particleId.Get());
680  pfoParameters.m_mass = PdgTable::GetParticleMass(pfoParameters.m_particleId.Get());
681  pfoParameters.m_energy = 0.f;
682  pfoParameters.m_momentum = CartesianVector(0.f, 0.f, 0.f);
683  pfoParameters.m_clusterList = clusterList;
684 
685  const ParticleFlowObject *pDaughterPfo(NULL);
686  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::Create(*this, pfoParameters, pDaughterPfo));
687 
688  if (!pPfoList->empty())
689  {
690  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Pfo>(*this, m_daughterPfoListName));
691  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SetPfoParentDaughterRelationship(*this, pParentPfo, pDaughterPfo));
692  }
693 }
694 
695 //------------------------------------------------------------------------------------------------------------------------------------------
696 
697 void DeltaRayMatchingAlgorithm::AddToDaughterPfo(const ClusterList &clusterList, const ParticleFlowObject *const pParentPfo) const
698 {
699  for (const Cluster *const pDaughterCluster : clusterList)
700  {
701  const HitType hitType(LArClusterHelper::GetClusterHitType(pDaughterCluster));
702  const std::string clusterListName((TPC_VIEW_U == hitType) ? m_inputClusterListNameU :
703  (TPC_VIEW_V == hitType) ? m_inputClusterListNameV : m_inputClusterListNameW);
704 
705  ClusterList pfoClusters;
706  LArPfoHelper::GetClusters(pParentPfo, hitType, pfoClusters);
707 
708  if (pfoClusters.empty())
709  throw StatusCodeException(STATUS_CODE_FAILURE);
710 
711  const Cluster *const pParentCluster = *(pfoClusters.begin());
712 
713  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*this, pParentCluster, pDaughterCluster,
714  clusterListName, clusterListName));
715  }
716 }
717 
718 //------------------------------------------------------------------------------------------------------------------------------------------
719 //------------------------------------------------------------------------------------------------------------------------------------------
720 
721 DeltaRayMatchingAlgorithm::Particle::Particle(const Cluster *const pCluster1, const Cluster *const pCluster2, const Cluster *const pCluster3,
722  const ParticleFlowObject *const pPfo) :
723  m_pClusterU(NULL),
724  m_pClusterV(NULL),
725  m_pClusterW(NULL),
726  m_pParentPfo(NULL)
727 {
728  const HitType hitType1(NULL != pCluster1 ? LArClusterHelper::GetClusterHitType(pCluster1) : HIT_CUSTOM);
729  const HitType hitType2(NULL != pCluster2 ? LArClusterHelper::GetClusterHitType(pCluster2) : HIT_CUSTOM);
730  const HitType hitType3(NULL != pCluster3 ? LArClusterHelper::GetClusterHitType(pCluster3) : HIT_CUSTOM);
731 
732  m_pClusterU = ((TPC_VIEW_U == hitType1) ? pCluster1 : (TPC_VIEW_U == hitType2) ? pCluster2 : (TPC_VIEW_U == hitType3) ? pCluster3 : NULL);
733  m_pClusterV = ((TPC_VIEW_V == hitType1) ? pCluster1 : (TPC_VIEW_V == hitType2) ? pCluster2 : (TPC_VIEW_V == hitType3) ? pCluster3 : NULL);
734  m_pClusterW = ((TPC_VIEW_W == hitType1) ? pCluster1 : (TPC_VIEW_W == hitType2) ? pCluster2 : (TPC_VIEW_W == hitType3) ? pCluster3 : NULL);
735  m_pParentPfo = pPfo;
736 
737  if (NULL == m_pClusterU && NULL == m_pClusterV && NULL == m_pClusterW)
738  throw StatusCodeException(STATUS_CODE_FAILURE);
739 }
740 
741 //------------------------------------------------------------------------------------------------------------------------------------------
742 
744 {
745  unsigned int numViews(0);
746 
747  if (NULL != m_pClusterU)
748  numViews += 1;
749 
750  if (NULL != m_pClusterV)
751  numViews += 1;
752 
753  if (NULL != m_pClusterW)
754  numViews += 1;
755 
756  return numViews;
757 }
758 
759 //------------------------------------------------------------------------------------------------------------------------------------------
760 
762 {
763  unsigned int numCaloHits(0);
764 
765  if (NULL != m_pClusterU)
766  numCaloHits += m_pClusterU->GetNCaloHits();
767 
768  if (NULL != m_pClusterV)
769  numCaloHits += m_pClusterV->GetNCaloHits();
770 
771  if (NULL != m_pClusterW)
772  numCaloHits += m_pClusterW->GetNCaloHits();
773 
774  return numCaloHits;
775 }
776 
777 //------------------------------------------------------------------------------------------------------------------------------------------
778 //------------------------------------------------------------------------------------------------------------------------------------------
779 
780 StatusCode DeltaRayMatchingAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
781 {
782  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "ParentPfoListName", m_parentPfoListName));
783  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "DaughterPfoListName", m_daughterPfoListName));
784  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameU", m_inputClusterListNameU));
785  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameV", m_inputClusterListNameV));
786  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameW", m_inputClusterListNameW));
787 
788  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
789  "MinCaloHitsPerCluster", m_minCaloHitsPerCluster));
790 
791  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
792  "OverlapWindow", m_xOverlapWindow));
793 
794  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
795  "DistanceForMatching", m_distanceForMatching));
796 
797  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
798  "PseudoChi2Cut", m_pseudoChi2Cut));
799 
800  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
801  "SearchRegion1D", m_searchRegion1D));
802 
803  return STATUS_CODE_SUCCESS;
804 }
805 
806 } // 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.
Header file for the pfo helper class.
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.
std::unordered_map< const pandora::Cluster *, float > ClusterLengthMap
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.
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterToClustersMap
unsigned int GetNCaloHits() const
Get number of calo hits.
Class that implements the KDTree partition of 2D space and a closest point search algorithm...
std::unordered_map< const pandora::ParticleFlowObject *, float > PfoLengthMap
Box structure used to define 2D field. It&#39;s used in KDTree building step to divide the detector space...
static void GetClusterSpanZ(const pandora::Cluster *const pCluster, const float xmin, const float xmax, float &zmin, float &zmax)
Get upper and lower Z positions of the calo hits in a cluster in range xmin to xmax.
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.
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.
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.
Int_t max
Definition: plot.C:27
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...
intermediate_table::const_iterator const_iterator
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.
void ThreeViewMatching(ClusterLengthMap &clusterLengthMap) const
Match clusters using all three views.
void InitializeNearbyClusterMaps()
Initialize nearby cluster maps.
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.
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.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
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.
Int_t min
Definition: plot.C:26
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.
std::unordered_map< const pandora::CaloHit *, const pandora::Cluster * > HitToClusterMap
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.
static void GetClusterSpanX(const pandora::Cluster *const pCluster, float &xmin, float &xmax)
Get minimum and maximum X positions of the calo hits in a cluster.
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.
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
Char_t n[5]
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 build(std::vector< KDTreeNodeInfoT< DATA, DIM > > &eltList, const KDTreeBoxT< DIM > &region)
Build the KD tree from the "eltList" in the space define by "region".
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.