LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
CosmicRayTrackRecoveryAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
12 
16 
17 using namespace pandora;
18 
19 namespace lar_content
20 {
21 
22 CosmicRayTrackRecoveryAlgorithm::CosmicRayTrackRecoveryAlgorithm() :
23  m_clusterMinLength(10.f),
24  m_clusterMinSpanZ(2.f),
25  m_clusterMinOverlapX(6.f),
26  m_clusterMaxDeltaX(3.f),
27  m_clusterMinHits(3)
28 {
29 }
30 
31 //------------------------------------------------------------------------------------------------------------------------------------------
32 
34 {
35  // Get the available clusters for each view
36  ClusterVector availableClustersU, availableClustersV, availableClustersW;
37  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->GetAvailableClusters(m_inputClusterListNameU, availableClustersU));
38  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->GetAvailableClusters(m_inputClusterListNameV, availableClustersV));
39  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->GetAvailableClusters(m_inputClusterListNameW, availableClustersW));
40 
41  // Select clean clusters in each view
42  ClusterVector cleanClustersU, cleanClustersV, cleanClustersW;
43  this->SelectCleanClusters(availableClustersU, cleanClustersU);
44  this->SelectCleanClusters(availableClustersV, cleanClustersV);
45  this->SelectCleanClusters(availableClustersW, cleanClustersW);
46 
47  // Calculate sliding fit results for clean clusters
48  TwoDSlidingFitResultMap slidingFitResultMap;
49  this->BuildSlidingFitResultMap(cleanClustersU, slidingFitResultMap);
50  this->BuildSlidingFitResultMap(cleanClustersV, slidingFitResultMap);
51  this->BuildSlidingFitResultMap(cleanClustersW, slidingFitResultMap);
52 
53  // Match clusters between pairs of views (using start/end information)
54  ClusterAssociationMap matchedClustersUV, matchedClustersVW, matchedClustersWU;
55  this->MatchViews(cleanClustersU, cleanClustersV, slidingFitResultMap, matchedClustersUV);
56  this->MatchViews(cleanClustersV, cleanClustersW, slidingFitResultMap, matchedClustersVW);
57  this->MatchViews(cleanClustersW, cleanClustersU, slidingFitResultMap, matchedClustersWU);
58 
59  // Create candidate particles using one, two and three primary views
60  ParticleList candidateParticles;
61 
62  this->MatchThreeViews(cleanClustersU, cleanClustersV, cleanClustersW, matchedClustersUV, matchedClustersVW, matchedClustersWU, candidateParticles);
63 
64  this->MatchTwoViews(cleanClustersU, cleanClustersV, cleanClustersW, matchedClustersUV, matchedClustersVW, matchedClustersWU, candidateParticles);
65 
66  this->MatchOneView(cleanClustersU, cleanClustersV, cleanClustersW, matchedClustersUV, matchedClustersVW, matchedClustersWU, candidateParticles);
67 
68  // Build particle flow objects from candidate particles
69  this->BuildParticles(candidateParticles);
70 
71  return STATUS_CODE_SUCCESS;
72 }
73 
74 //------------------------------------------------------------------------------------------------------------------------------------------
75 
76 StatusCode CosmicRayTrackRecoveryAlgorithm::GetAvailableClusters(const std::string &inputClusterListName, ClusterVector &clusterVector) const
77 {
78  const ClusterList *pClusterList = NULL;
79  PANDORA_RETURN_RESULT_IF_AND_IF(
80  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this, inputClusterListName, pClusterList))
81 
82  if (!pClusterList || pClusterList->empty())
83  {
84  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
85  std::cout << "CosmicRayTrackRecoveryAlgorithm: unable to find cluster list " << inputClusterListName << std::endl;
86 
87  return STATUS_CODE_SUCCESS;
88  }
89 
90  for (const Cluster *const pCluster : *pClusterList)
91  {
92  if (PandoraContentApi::IsAvailable(*this, pCluster))
93  clusterVector.push_back(pCluster);
94  }
95 
96  std::sort(clusterVector.begin(), clusterVector.end(), LArClusterHelper::SortByNHits);
97 
98  return STATUS_CODE_SUCCESS;
99 }
100 
101 //------------------------------------------------------------------------------------------------------------------------------------------
102 
104 {
105  for (ClusterVector::const_iterator iter = inputVector.begin(), iterEnd = inputVector.end(); iter != iterEnd; ++iter)
106  {
107  const Cluster *const pCluster = *iter;
108 
109  // Remove clusters with insufficient hits for a sliding fit
110  if (pCluster->GetNCaloHits() < m_clusterMinHits)
111  continue;
112  // Remove clusters below a minimum length
114  continue;
115 
116  // Remove clusters nearly parallel to Z or X
117  CartesianVector minCoordinate(0.f, 0.f, 0.f);
118  CartesianVector maxCoordinate(0.f, 0.f, 0.f);
119  LArClusterHelper::GetClusterBoundingBox(pCluster, minCoordinate, maxCoordinate);
120 
121  const CartesianVector deltaCoordinate(maxCoordinate - minCoordinate);
122  if (std::fabs(deltaCoordinate.GetZ()) < m_clusterMinSpanZ || std::fabs(deltaCoordinate.GetX()) < m_clusterMinOverlapX)
123  continue;
124 
125  outputVector.push_back(pCluster);
126  }
127 }
128 
129 //------------------------------------------------------------------------------------------------------------------------------------------
130 
132 {
133  const unsigned int m_halfWindowLayers(25);
134 
135  for (ClusterVector::const_iterator iter = clusterVector.begin(), iterEnd = clusterVector.end(); iter != iterEnd; ++iter)
136  {
137  if (slidingFitResultMap.end() == slidingFitResultMap.find(*iter))
138  {
139  try
140  {
141  const float slidingFitPitch(LArGeometryHelper::GetWirePitch(this->GetPandora(), LArClusterHelper::GetClusterHitType(*iter)));
142  const TwoDSlidingFitResult slidingFitResult(*iter, m_halfWindowLayers, slidingFitPitch);
143 
144  if (!slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(*iter, slidingFitResult)).second)
145  throw StatusCodeException(STATUS_CODE_FAILURE);
146  }
147  catch (StatusCodeException &statusCodeException)
148  {
149  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
150  throw statusCodeException;
151  }
152  }
153  }
154 }
155 
156 //------------------------------------------------------------------------------------------------------------------------------------------
157 
158 void CosmicRayTrackRecoveryAlgorithm::MatchViews(const ClusterVector &clusterVector1, const ClusterVector &clusterVector2,
159  const TwoDSlidingFitResultMap &slidingFitResultMap, ClusterAssociationMap &clusterAssociationMap) const
160 {
161  for (ClusterVector::const_iterator iter1 = clusterVector1.begin(), iterEnd1 = clusterVector1.end(); iter1 != iterEnd1; ++iter1)
162  this->MatchClusters(*iter1, clusterVector2, slidingFitResultMap, clusterAssociationMap);
163 
164  for (ClusterVector::const_iterator iter2 = clusterVector2.begin(), iterEnd2 = clusterVector2.end(); iter2 != iterEnd2; ++iter2)
165  this->MatchClusters(*iter2, clusterVector1, slidingFitResultMap, clusterAssociationMap);
166 }
167 
168 //------------------------------------------------------------------------------------------------------------------------------------------
169 
170 void CosmicRayTrackRecoveryAlgorithm::MatchClusters(const Cluster *const pSeedCluster, const ClusterVector &targetClusters,
171  const TwoDSlidingFitResultMap &slidingFitResultMap, ClusterAssociationMap &clusterAssociationMap) const
172 {
173  // Match seed cluster to target clusters according to alignment in X position of start/end positions
174  // Two possible matches: (a) one-to-one associations where both the track start and end positions match up
175  // (b) one-to-two associations where the track is split into two clusters in one view
176  // Require overlap in X (according to clusterMinOverlapX) and alignment in X (according to clusterMaxDeltaX)
177 
178  TwoDSlidingFitResultMap::const_iterator fsIter = slidingFitResultMap.find(pSeedCluster);
179 
180  if (slidingFitResultMap.end() == fsIter)
181  throw StatusCodeException(STATUS_CODE_FAILURE);
182 
183  const TwoDSlidingFitResult &slidingFitResult1(fsIter->second);
184  const CartesianVector &innerVertex1(slidingFitResult1.GetGlobalMinLayerPosition());
185  const CartesianVector &outerVertex1(slidingFitResult1.GetGlobalMaxLayerPosition());
186  const float xSpan1(std::fabs(outerVertex1.GetX() - innerVertex1.GetX()));
187 
188  const Cluster *pBestClusterInner(NULL);
189  const Cluster *pBestClusterOuter(NULL);
190  const Cluster *pBestCluster(NULL);
191 
192  float bestDisplacementInner(m_clusterMaxDeltaX);
193  float bestDisplacementOuter(m_clusterMaxDeltaX);
194  float bestDisplacement(2.f * m_clusterMaxDeltaX);
195 
196  for (ClusterVector::const_iterator tIter = targetClusters.begin(), tIterEnd = targetClusters.end(); tIter != tIterEnd; ++tIter)
197  {
198  const Cluster *const pTargetCluster = *tIter;
199 
200  UIntSet daughterVolumeIntersection;
201  LArGeometryHelper::GetCommonDaughterVolumes(pSeedCluster, pTargetCluster, daughterVolumeIntersection);
202 
203  if (daughterVolumeIntersection.empty())
204  continue;
205 
207  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
208 
209  TwoDSlidingFitResultMap::const_iterator ftIter = slidingFitResultMap.find(*tIter);
210 
211  if (slidingFitResultMap.end() == ftIter)
212  throw StatusCodeException(STATUS_CODE_FAILURE);
213 
214  const TwoDSlidingFitResult &slidingFitResult2(ftIter->second);
215  const CartesianVector &innerVertex2(slidingFitResult2.GetGlobalMinLayerPosition());
216  const CartesianVector &outerVertex2(slidingFitResult2.GetGlobalMaxLayerPosition());
217  const float xSpan2(std::fabs(outerVertex2.GetX() - innerVertex2.GetX()));
218 
219  if (xSpan2 > 1.5f * xSpan1)
220  continue;
221 
222  const float xMin1(std::min(innerVertex1.GetX(), outerVertex1.GetX()));
223  const float xMax1(std::max(innerVertex1.GetX(), outerVertex1.GetX()));
224  const float xMin2(std::min(innerVertex2.GetX(), outerVertex2.GetX()));
225  const float xMax2(std::max(innerVertex2.GetX(), outerVertex2.GetX()));
226  const float xOverlap(std::min(xMax1, xMax2) - std::max(xMin1, xMin2));
227 
228  if (xOverlap < m_clusterMinOverlapX)
229  continue;
230 
231  const float dxMin(std::fabs(xMin2 - xMin1));
232  const float dxMax(std::fabs(xMax2 - xMax1));
233 
234  if (dxMin < bestDisplacementInner)
235  {
236  pBestClusterInner = pTargetCluster;
237  bestDisplacementInner = dxMin;
238  }
239 
240  if (dxMax < bestDisplacementOuter)
241  {
242  pBestClusterOuter = pTargetCluster;
243  bestDisplacementOuter = dxMax;
244  }
245 
246  if (dxMin + dxMax < bestDisplacement)
247  {
248  pBestCluster = pTargetCluster;
249  bestDisplacement = dxMin + dxMax;
250  }
251  }
252 
253  if (pBestCluster)
254  {
255  ClusterList &seedList(clusterAssociationMap[pSeedCluster]);
256 
257  if (seedList.end() == std::find(seedList.begin(), seedList.end(), pBestCluster))
258  seedList.push_back(pBestCluster);
259 
260  ClusterList &bestList(clusterAssociationMap[pBestCluster]);
261 
262  if (bestList.end() == std::find(bestList.begin(), bestList.end(), pSeedCluster))
263  bestList.push_back(pSeedCluster);
264  }
265  else if (pBestClusterInner && pBestClusterOuter)
266  {
267  TwoDSlidingFitResultMap::const_iterator iterInner = slidingFitResultMap.find(pBestClusterInner);
268  TwoDSlidingFitResultMap::const_iterator iterOuter = slidingFitResultMap.find(pBestClusterOuter);
269 
270  if (slidingFitResultMap.end() == iterInner || slidingFitResultMap.end() == iterOuter)
271  throw StatusCodeException(STATUS_CODE_FAILURE);
272 
273  const LArPointingCluster pointingClusterInner(iterInner->second);
274  const LArPointingCluster pointingClusterOuter(iterOuter->second);
275 
276  LArPointingCluster::Vertex pointingVertexInner, pointingVertexOuter;
277 
278  try
279  {
280  LArPointingClusterHelper::GetClosestVertices(pointingClusterInner, pointingClusterOuter, pointingVertexInner, pointingVertexOuter);
281  }
282  catch (StatusCodeException &)
283  {
284  return;
285  }
286 
287  const LArPointingCluster::Vertex pointingEndInner(
288  pointingVertexInner.IsInnerVertex() ? pointingClusterInner.GetOuterVertex() : pointingClusterInner.GetInnerVertex());
289  const LArPointingCluster::Vertex pointingEndOuter(
290  pointingVertexOuter.IsInnerVertex() ? pointingClusterOuter.GetOuterVertex() : pointingClusterOuter.GetInnerVertex());
291 
292  const float rSpan((pointingEndInner.GetPosition() - pointingEndOuter.GetPosition()).GetMagnitude());
293 
294  if (LArPointingClusterHelper::IsEmission(pointingVertexInner.GetPosition(), pointingVertexOuter, -1.f, 0.75f * rSpan, 5.f, 10.f) &&
295  LArPointingClusterHelper::IsEmission(pointingVertexOuter.GetPosition(), pointingVertexInner, -1.f, 0.75f * rSpan, 5.f, 10.f))
296  {
297  ClusterList &bestInnerList(clusterAssociationMap[pBestClusterInner]);
298 
299  if (bestInnerList.end() == std::find(bestInnerList.begin(), bestInnerList.end(), pSeedCluster))
300  bestInnerList.push_back(pSeedCluster);
301 
302  ClusterList &bestOuterList(clusterAssociationMap[pBestClusterOuter]);
303 
304  if (bestOuterList.end() == std::find(bestOuterList.begin(), bestOuterList.end(), pSeedCluster))
305  bestOuterList.push_back(pSeedCluster);
306  }
307  }
308 }
309 
310 //------------------------------------------------------------------------------------------------------------------------------------------
311 
312 void CosmicRayTrackRecoveryAlgorithm::MatchThreeViews(const ClusterVector &clusterVectorU, const ClusterVector &clusterVectorV,
313  const ClusterVector &clusterVectorW, const ClusterAssociationMap &matchedClustersUV, const ClusterAssociationMap &matchedClustersVW,
314  const ClusterAssociationMap &matchedClustersWU, ParticleList &particleList) const
315 {
316  ClusterSet vetoList;
317  this->BuildVetoList(particleList, vetoList);
318 
319  ParticleList newParticleList;
320 
321  const ClusterVector &clusterVector1(clusterVectorU);
322  const ClusterVector &clusterVector2(clusterVectorV);
323  const ClusterVector &clusterVector3(clusterVectorW);
324 
325  const ClusterAssociationMap &matchedClusters12(matchedClustersUV);
326  const ClusterAssociationMap &matchedClusters23(matchedClustersVW);
327  const ClusterAssociationMap &matchedClusters31(matchedClustersWU);
328 
329  for (ClusterVector::const_iterator iter1 = clusterVector1.begin(), iterEnd1 = clusterVector1.end(); iter1 != iterEnd1; ++iter1)
330  {
331  const Cluster *const pCluster1 = *iter1;
332 
333  if (vetoList.count(pCluster1))
334  continue;
335 
336  const ClusterAssociationMap::const_iterator iter311 = matchedClusters31.find(pCluster1);
337  const ClusterList matchedClusters31_pCluster1(iter311 != matchedClusters31.end() ? iter311->second : ClusterList());
338 
339  const ClusterAssociationMap::const_iterator iter121 = matchedClusters12.find(pCluster1);
340  const ClusterList matchedClusters12_pCluster1(iter121 != matchedClusters12.end() ? iter121->second : ClusterList());
341 
342  for (ClusterVector::const_iterator iter2 = clusterVector2.begin(), iterEndV = clusterVector2.end(); iter2 != iterEndV; ++iter2)
343  {
344  const Cluster *const pCluster2 = *iter2;
345 
346  if (vetoList.count(pCluster2))
347  continue;
348 
349  const ClusterAssociationMap::const_iterator iter122 = matchedClusters12.find(pCluster2);
350  const ClusterList matchedClusters12_pCluster2(iter122 != matchedClusters12.end() ? iter122->second : ClusterList());
351 
352  const ClusterAssociationMap::const_iterator iter232 = matchedClusters23.find(pCluster2);
353  const ClusterList matchedClusters23_pCluster2(iter232 != matchedClusters23.end() ? iter232->second : ClusterList());
354 
355  for (ClusterVector::const_iterator iter3 = clusterVector3.begin(), iterEnd3 = clusterVector3.end(); iter3 != iterEnd3; ++iter3)
356  {
357  const Cluster *const pCluster3 = *iter3;
358 
359  if (vetoList.count(pCluster3))
360  continue;
361 
362  const ClusterAssociationMap::const_iterator iter233 = matchedClusters23.find(pCluster3);
363  const ClusterList matchedClusters23_pCluster3(iter233 != matchedClusters23.end() ? iter233->second : ClusterList());
364 
365  const ClusterAssociationMap::const_iterator iter313 = matchedClusters31.find(pCluster3);
366  const ClusterList matchedClusters31_pCluster3(iter313 != matchedClusters31.end() ? iter313->second : ClusterList());
367 
368  const bool match12((matchedClusters12_pCluster1.size() + matchedClusters12_pCluster2.size() > 0) &&
369  ((matchedClusters12_pCluster1.size() == 1 &&
370  std::find(matchedClusters12_pCluster1.begin(), matchedClusters12_pCluster1.end(), pCluster2) !=
371  matchedClusters12_pCluster1.end()) ||
372  (matchedClusters12_pCluster1.size() == 0)) &&
373  ((matchedClusters12_pCluster2.size() == 1 &&
374  std::find(matchedClusters12_pCluster2.begin(), matchedClusters12_pCluster2.end(), pCluster1) !=
375  matchedClusters12_pCluster2.end()) ||
376  (matchedClusters12_pCluster2.size() == 0)));
377 
378  const bool match23((matchedClusters23_pCluster2.size() + matchedClusters23_pCluster3.size() > 0) &&
379  ((matchedClusters23_pCluster2.size() == 1 &&
380  std::find(matchedClusters23_pCluster2.begin(), matchedClusters23_pCluster2.end(), pCluster3) !=
381  matchedClusters23_pCluster2.end()) ||
382  (matchedClusters23_pCluster2.size() == 0)) &&
383  ((matchedClusters23_pCluster3.size() == 1 &&
384  std::find(matchedClusters23_pCluster3.begin(), matchedClusters23_pCluster3.end(), pCluster2) !=
385  matchedClusters23_pCluster3.end()) ||
386  (matchedClusters23_pCluster3.size() == 0)));
387 
388  const bool match31((matchedClusters31_pCluster3.size() + matchedClusters31_pCluster1.size() > 0) &&
389  ((matchedClusters31_pCluster3.size() == 1 &&
390  std::find(matchedClusters31_pCluster3.begin(), matchedClusters31_pCluster3.end(), pCluster1) !=
391  matchedClusters31_pCluster3.end()) ||
392  (matchedClusters31_pCluster3.size() == 0)) &&
393  ((matchedClusters31_pCluster1.size() == 1 &&
394  std::find(matchedClusters31_pCluster1.begin(), matchedClusters31_pCluster1.end(), pCluster3) !=
395  matchedClusters31_pCluster1.end()) ||
396  (matchedClusters31_pCluster1.size() == 0)));
397 
398  if (match12 && match23 && match31)
399  {
400  Particle newParticle;
401  newParticle.m_clusterList.push_back(pCluster1);
402  newParticle.m_clusterList.push_back(pCluster2);
403  newParticle.m_clusterList.push_back(pCluster3);
404  newParticleList.push_back(newParticle);
405  }
406  }
407  }
408  }
409 
410  return this->RemoveAmbiguities(newParticleList, particleList);
411 }
412 
413 //------------------------------------------------------------------------------------------------------------------------------------------
414 
415 void CosmicRayTrackRecoveryAlgorithm::MatchTwoViews(const ClusterVector &clusterVectorU, const ClusterVector &clusterVectorV,
416  const ClusterVector &clusterVectorW, const ClusterAssociationMap &matchedClustersUV, const ClusterAssociationMap &matchedClustersVW,
417  const ClusterAssociationMap &matchedClustersWU, ParticleList &particleList) const
418 {
419  ClusterSet vetoList;
420  this->BuildVetoList(particleList, vetoList);
421 
422  ParticleList newParticleList;
423 
424  for (unsigned int iView = 0; iView < 3; ++iView)
425  {
426  const ClusterVector &clusterVector1((0 == iView) ? clusterVectorU : (1 == iView) ? clusterVectorV : clusterVectorW);
427  const ClusterVector &clusterVector2((0 == iView) ? clusterVectorV : (1 == iView) ? clusterVectorW : clusterVectorU);
428  const ClusterVector &clusterVector3((0 == iView) ? clusterVectorW : (1 == iView) ? clusterVectorU : clusterVectorV);
429 
430  const ClusterAssociationMap &matchedClusters12(((0 == iView) ? matchedClustersUV
431  : (1 == iView) ? matchedClustersVW
432  : matchedClustersWU));
433  const ClusterAssociationMap &matchedClusters23(((0 == iView) ? matchedClustersVW
434  : (1 == iView) ? matchedClustersWU
435  : matchedClustersUV));
436  const ClusterAssociationMap &matchedClusters31(((0 == iView) ? matchedClustersWU
437  : (1 == iView) ? matchedClustersUV
438  : matchedClustersVW));
439 
440  for (ClusterVector::const_iterator iter1 = clusterVector1.begin(), iterEnd1 = clusterVector1.end(); iter1 != iterEnd1; ++iter1)
441  {
442  const Cluster *const pCluster1 = *iter1;
443 
444  if (vetoList.count(pCluster1))
445  continue;
446 
447  const ClusterAssociationMap::const_iterator iter311 = matchedClusters31.find(pCluster1);
448  const ClusterList matchedClusters31_pCluster1(iter311 != matchedClusters31.end() ? iter311->second : ClusterList());
449 
450  const ClusterAssociationMap::const_iterator iter121 = matchedClusters12.find(pCluster1);
451  const ClusterList matchedClusters12_pCluster1(iter121 != matchedClusters12.end() ? iter121->second : ClusterList());
452 
453  for (ClusterVector::const_iterator iter2 = clusterVector2.begin(), iterEnd2 = clusterVector2.end(); iter2 != iterEnd2; ++iter2)
454  {
455  const Cluster *const pCluster2 = *iter2;
456 
457  if (vetoList.count(pCluster2))
458  continue;
459 
460  const ClusterAssociationMap::const_iterator iter122 = matchedClusters12.find(pCluster2);
461  const ClusterList matchedClusters12_pCluster2(iter122 != matchedClusters12.end() ? iter122->second : ClusterList());
462 
463  const ClusterAssociationMap::const_iterator iter232 = matchedClusters23.find(pCluster2);
464  const ClusterList matchedClusters23_pCluster2(iter232 != matchedClusters23.end() ? iter232->second : ClusterList());
465 
466  const bool match12((matchedClusters12_pCluster1.size() == 1 &&
467  std::find(matchedClusters12_pCluster1.begin(), matchedClusters12_pCluster1.end(), pCluster2) !=
468  matchedClusters12_pCluster1.end()) &&
469  (matchedClusters12_pCluster2.size() == 1 &&
470  std::find(matchedClusters12_pCluster2.begin(), matchedClusters12_pCluster2.end(), pCluster1) !=
471  matchedClusters12_pCluster2.end()) &&
472  (matchedClusters23_pCluster2.size() == 0 && matchedClusters31_pCluster1.size() == 0));
473 
474  if (!match12)
475  continue;
476 
477  Particle newParticle;
478  newParticle.m_clusterList.push_back(pCluster1);
479  newParticle.m_clusterList.push_back(pCluster2);
480 
481  for (ClusterVector::const_iterator iter3 = clusterVector3.begin(), iterEnd3 = clusterVector3.end(); iter3 != iterEnd3; ++iter3)
482  {
483  const Cluster *const pCluster3 = *iter3;
484 
485  if (vetoList.count(pCluster3))
486  continue;
487 
488  const ClusterAssociationMap::const_iterator iter233 = matchedClusters23.find(pCluster3);
489  const ClusterList matchedClusters23_pCluster3(iter233 != matchedClusters23.end() ? iter233->second : ClusterList());
490 
491  const ClusterAssociationMap::const_iterator iter313 = matchedClusters31.find(pCluster3);
492  const ClusterList matchedClusters31_pCluster3(iter313 != matchedClusters31.end() ? iter313->second : ClusterList());
493 
494  const bool match3((matchedClusters31_pCluster3.size() + matchedClusters23_pCluster3.size() > 0) &&
495  ((matchedClusters31_pCluster3.size() == 1 &&
496  std::find(matchedClusters31_pCluster3.begin(), matchedClusters31_pCluster3.end(), pCluster1) !=
497  matchedClusters31_pCluster3.end()) ||
498  (matchedClusters31_pCluster3.size() == 0)) &&
499  ((matchedClusters23_pCluster3.size() == 1 &&
500  std::find(matchedClusters23_pCluster3.begin(), matchedClusters23_pCluster3.end(), pCluster2) !=
501  matchedClusters23_pCluster3.end()) ||
502  (matchedClusters23_pCluster3.size() == 0)));
503 
504  if (match3)
505  newParticle.m_clusterList.push_back(pCluster3);
506  }
507 
508  newParticleList.push_back(newParticle);
509  }
510  }
511  }
512 
513  return this->RemoveAmbiguities(newParticleList, particleList);
514 }
515 
516 //------------------------------------------------------------------------------------------------------------------------------------------
517 
518 void CosmicRayTrackRecoveryAlgorithm::MatchOneView(const ClusterVector &clusterVectorU, const ClusterVector &clusterVectorV,
519  const ClusterVector &clusterVectorW, const ClusterAssociationMap &matchedClustersUV, const ClusterAssociationMap &matchedClustersVW,
520  const ClusterAssociationMap &matchedClustersWU, ParticleList &particleList) const
521 {
522  ClusterSet vetoList;
523  this->BuildVetoList(particleList, vetoList);
524 
525  ParticleList newParticleList;
526 
527  for (unsigned int iView = 0; iView < 3; ++iView)
528  {
529  const ClusterVector &clusterVector1((0 == iView) ? clusterVectorU : (1 == iView) ? clusterVectorV : clusterVectorW);
530  const ClusterVector &clusterVector2((0 == iView) ? clusterVectorV : (1 == iView) ? clusterVectorW : clusterVectorU);
531  const ClusterVector &clusterVector3((0 == iView) ? clusterVectorW : (1 == iView) ? clusterVectorU : clusterVectorV);
532 
533  const ClusterAssociationMap &matchedClusters12(((0 == iView) ? matchedClustersUV
534  : (1 == iView) ? matchedClustersVW
535  : matchedClustersWU));
536  const ClusterAssociationMap &matchedClusters23(((0 == iView) ? matchedClustersVW
537  : (1 == iView) ? matchedClustersWU
538  : matchedClustersUV));
539  const ClusterAssociationMap &matchedClusters31(((0 == iView) ? matchedClustersWU
540  : (1 == iView) ? matchedClustersUV
541  : matchedClustersVW));
542 
543  for (ClusterVector::const_iterator iter1 = clusterVector1.begin(), iterEnd1 = clusterVector1.end(); iter1 != iterEnd1; ++iter1)
544  {
545  const Cluster *const pCluster1 = *iter1;
546 
547  if (vetoList.count(pCluster1))
548  continue;
549 
550  const ClusterAssociationMap::const_iterator iter311 = matchedClusters31.find(pCluster1);
551  const ClusterList matchedClusters31_pCluster1(iter311 != matchedClusters31.end() ? iter311->second : ClusterList());
552 
553  const ClusterAssociationMap::const_iterator iter121 = matchedClusters12.find(pCluster1);
554  const ClusterList matchedClusters12_pCluster1(iter121 != matchedClusters12.end() ? iter121->second : ClusterList());
555 
556  if (matchedClusters12_pCluster1.size() + matchedClusters31_pCluster1.size() > 0)
557  continue;
558 
559  Particle newParticle;
560  newParticle.m_clusterList.push_back(pCluster1);
561 
562  for (ClusterVector::const_iterator iter2 = clusterVector2.begin(), iterEnd2 = clusterVector2.end(); iter2 != iterEnd2; ++iter2)
563  {
564  const Cluster *const pCluster2 = *iter2;
565 
566  if (vetoList.count(pCluster2))
567  continue;
568 
569  const ClusterAssociationMap::const_iterator iter122 = matchedClusters12.find(pCluster2);
570  const ClusterList matchedClusters12_pCluster2(iter122 != matchedClusters12.end() ? iter122->second : ClusterList());
571 
572  const ClusterAssociationMap::const_iterator iter232 = matchedClusters23.find(pCluster2);
573  const ClusterList matchedClusters23_pCluster2(iter232 != matchedClusters23.end() ? iter232->second : ClusterList());
574 
575  if (matchedClusters12_pCluster2.size() == 1 &&
576  std::find(matchedClusters12_pCluster2.begin(), matchedClusters12_pCluster2.end(), pCluster1) !=
577  matchedClusters12_pCluster2.end() &&
578  matchedClusters23_pCluster2.size() == 0)
579  newParticle.m_clusterList.push_back(pCluster2);
580  }
581 
582  for (ClusterVector::const_iterator iter3 = clusterVector3.begin(), iterEnd3 = clusterVector3.end(); iter3 != iterEnd3; ++iter3)
583  {
584  const Cluster *const pCluster3 = *iter3;
585 
586  if (vetoList.count(pCluster3))
587  continue;
588 
589  const ClusterAssociationMap::const_iterator iter233 = matchedClusters23.find(pCluster3);
590  const ClusterList matchedClusters23_pCluster3(iter233 != matchedClusters23.end() ? iter233->second : ClusterList());
591 
592  const ClusterAssociationMap::const_iterator iter313 = matchedClusters31.find(pCluster3);
593  const ClusterList matchedClusters31_pCluster3(iter313 != matchedClusters31.end() ? iter313->second : ClusterList());
594 
595  if (matchedClusters31_pCluster3.size() == 1 &&
596  std::find(matchedClusters31_pCluster3.begin(), matchedClusters31_pCluster3.end(), pCluster1) !=
597  matchedClusters31_pCluster3.end() &&
598  matchedClusters23_pCluster3.size() == 0)
599  newParticle.m_clusterList.push_back(pCluster3);
600  }
601 
602  if (newParticle.m_clusterList.size() > 1)
603  newParticleList.push_back(newParticle);
604  }
605  }
606 
607  return this->RemoveAmbiguities(newParticleList, particleList);
608 }
609 
610 //------------------------------------------------------------------------------------------------------------------------------------------
611 
612 void CosmicRayTrackRecoveryAlgorithm::BuildVetoList(const ParticleList &particleList, ClusterSet &vetoList) const
613 {
614  for (ParticleList::const_iterator pIter = particleList.begin(), pIterEnd = particleList.end(); pIter != pIterEnd; ++pIter)
615  {
616  const Particle &particle = *pIter;
617  vetoList.insert(particle.m_clusterList.begin(), particle.m_clusterList.end());
618  }
619 }
620 
621 //------------------------------------------------------------------------------------------------------------------------------------------
622 
623 void CosmicRayTrackRecoveryAlgorithm::RemoveAmbiguities(const ParticleList &inputParticleList, ParticleList &outputParticleList) const
624 {
625  for (ParticleList::const_iterator pIter1 = inputParticleList.begin(), pIterEnd1 = inputParticleList.end(); pIter1 != pIterEnd1; ++pIter1)
626  {
627  const Particle &particle1 = *pIter1;
628  const ClusterList &clusterList1 = particle1.m_clusterList;
629 
630  try
631  {
632  bool isUnique(true);
633 
634  for (ParticleList::const_iterator pIter2 = pIter1, pIterEnd2 = inputParticleList.end(); pIter2 != pIterEnd2; ++pIter2)
635  {
636  const Particle &particle2 = *pIter2;
637  const ClusterList &clusterList2 = particle2.m_clusterList;
638 
639  ClusterSet duplicateSet;
640 
641  for (ClusterList::const_iterator cIter1 = clusterList1.begin(), cIterEnd1 = clusterList1.end(); cIter1 != cIterEnd1; ++cIter1)
642  {
643  const Cluster *pCluster = *cIter1;
644 
645  if (clusterList2.end() != std::find(clusterList2.begin(), clusterList2.end(), pCluster))
646  duplicateSet.insert(pCluster);
647  }
648 
649  if (duplicateSet.size() > 0 && clusterList1.size() != clusterList2.size())
650  {
651  isUnique = false;
652  break;
653  }
654  }
655 
656  if (!isUnique)
657  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
658 
659  outputParticleList.push_back(particle1);
660  }
661  catch (StatusCodeException &)
662  {
663  std::cout << " Warning in CosmicRayTrackRecoveryAlgorithm: found duplicate particles in candidate list " << std::endl;
664  }
665  }
666 }
667 
668 //------------------------------------------------------------------------------------------------------------------------------------------
669 
671 {
672  if (particleList.empty())
673  return;
674 
675  const PfoList *pPfoList(nullptr);
676  std::string pfoListName;
677  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pPfoList, pfoListName));
678 
679  for (const Particle &particle : particleList)
680  {
681  if (!PandoraContentApi::IsAvailable(*this, &particle.m_clusterList))
682  continue;
683 
684  ClusterList clusterList;
685  this->MergeClusters(particle.m_clusterList, clusterList);
686 
687  if (clusterList.empty())
688  throw StatusCodeException(STATUS_CODE_FAILURE);
689 
690  PandoraContentApi::ParticleFlowObject::Parameters pfoParameters;
691  pfoParameters.m_particleId = MU_MINUS; // TRACK
692  pfoParameters.m_charge = PdgTable::GetParticleCharge(pfoParameters.m_particleId.Get());
693  pfoParameters.m_mass = PdgTable::GetParticleMass(pfoParameters.m_particleId.Get());
694  pfoParameters.m_energy = 0.f;
695  pfoParameters.m_momentum = CartesianVector(0.f, 0.f, 0.f);
696  pfoParameters.m_clusterList = clusterList;
697 
698  const ParticleFlowObject *pPfo(nullptr);
699  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::Create(*this, pfoParameters, pPfo));
700  }
701 
702  if (!pPfoList->empty())
703  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Pfo>(*this, m_outputPfoListName));
704 }
705 
706 //------------------------------------------------------------------------------------------------------------------------------------------
707 
708 void CosmicRayTrackRecoveryAlgorithm::MergeClusters(const ClusterList &inputClusterList, ClusterList &outputClusterList) const
709 {
710  ClusterList clusterListU, clusterListV, clusterListW;
711  LArClusterHelper::GetClustersByHitType(inputClusterList, TPC_VIEW_U, clusterListU);
712  LArClusterHelper::GetClustersByHitType(inputClusterList, TPC_VIEW_V, clusterListV);
713  LArClusterHelper::GetClustersByHitType(inputClusterList, TPC_VIEW_W, clusterListW);
714 
715  for (unsigned int iView = 0; iView < 3; ++iView)
716  {
717  const ClusterList clusterList((0 == iView) ? clusterListU : (1 == iView) ? clusterListV : clusterListW);
718  const std::string inputClusterListName((0 == iView) ? m_inputClusterListNameU
719  : (1 == iView) ? m_inputClusterListNameV
721 
722  if (clusterList.empty())
723  continue;
724 
725  const Cluster *const pSeedCluster(clusterList.front());
726 
727  if (!PandoraContentApi::IsAvailable(*this, pSeedCluster))
728  throw StatusCodeException(STATUS_CODE_FAILURE);
729 
730  for (const Cluster *const pAssociatedCluster : clusterList)
731  {
732  if (pAssociatedCluster == pSeedCluster)
733  continue;
734 
735  if (!PandoraContentApi::IsAvailable(*this, pAssociatedCluster))
736  continue;
737 
738  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=,
739  PandoraContentApi::MergeAndDeleteClusters(*this, pSeedCluster, pAssociatedCluster, inputClusterListName, inputClusterListName));
740  }
741 
742  outputClusterList.push_back(pSeedCluster);
743  }
744 }
745 
746 //------------------------------------------------------------------------------------------------------------------------------------------
747 
748 StatusCode CosmicRayTrackRecoveryAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
749 {
750  PANDORA_RETURN_RESULT_IF_AND_IF(
751  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ClusterMinLength", m_clusterMinLength));
752 
753  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ClusterMinSpanZ", m_clusterMinSpanZ));
754 
755  PANDORA_RETURN_RESULT_IF_AND_IF(
756  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ClusterMinOverlapX", m_clusterMinOverlapX));
757 
758  PANDORA_RETURN_RESULT_IF_AND_IF(
759  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ClusterMaxDeltaX", m_clusterMaxDeltaX));
760 
761  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ClusterMinHits", m_clusterMinHits));
762 
763  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameU", m_inputClusterListNameU));
764  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameV", m_inputClusterListNameV));
765  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputClusterListNameW", m_inputClusterListNameW));
766  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "OutputPfoListName", m_outputPfoListName));
767 
768  return STATUS_CODE_SUCCESS;
769 }
770 
771 } // namespace lar_content
void BuildSlidingFitResultMap(const pandora::ClusterVector &clusterVector, TwoDSlidingFitResultMap &slidingFitResultMap) const
Build the map of sliding fit results.
void RemoveAmbiguities(const ParticleList &inputParticleList, ParticleList &outputParticleList) const
Remove particles with duplicate clusters.
static bool SortByNHits(const pandora::Cluster *const pLhs, const pandora::Cluster *const pRhs)
Sort clusters by number of hits, then layer span, then inner layer, then position, then pulse-height.
void MatchTwoViews(const pandora::ClusterVector &clusterVectorU, const pandora::ClusterVector &clusterVectorV, const pandora::ClusterVector &clusterVectorW, const ClusterAssociationMap &clusterAssociationMapUV, const ClusterAssociationMap &clusterAssociationMapVW, const ClusterAssociationMap &clusterAssociationMapWU, ParticleList &particleList) const
Create candidate particles using two primary clusters and one pair of broken clusters.
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterAssociationMap
void BuildParticles(const ParticleList &particleList)
Build particle flow objects.
static bool IsEmission(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxLongitudinalDistance, const float maxTransverseDistance, const float angularAllowance)
Whether pointing vertex is emitted from a given position.
void MatchOneView(const pandora::ClusterVector &clusterVectorU, const pandora::ClusterVector &clusterVectorV, const pandora::ClusterVector &clusterVectorW, const ClusterAssociationMap &clusterAssociationMapUV, const ClusterAssociationMap &clusterAssociationMapVW, const ClusterAssociationMap &clusterAssociationMapWU, ParticleList &particleList) const
Create candidate particles using one primary cluster and one pair of broken clusters.
void MatchClusters(const pandora::Cluster *const pSeedCluster, const pandora::ClusterVector &targetClusters, const TwoDSlidingFitResultMap &slidingFitResultMap, ClusterAssociationMap &clusterAssociationMap) const
Match a seed cluster with a list of target clusters and populate the cluster association map...
void BuildVetoList(const ParticleList &particleList, pandora::ClusterSet &vetoList) const
Build the list of clusters already used to create particles.
static void GetClustersByHitType(const pandora::ClusterList &inputClusters, const pandora::HitType hitType, pandora::ClusterList &clusterList)
Get the subset of clusters, from a provided list, that match the specified hit type.
intermediate_table::const_iterator const_iterator
LArPointingCluster class.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
static void GetClosestVertices(const bool useX, const bool useY, const bool useZ, const LArPointingCluster &pointingClusterI, const LArPointingCluster &pointingClusterJ, LArPointingCluster::Vertex &closestVertexI, LArPointingCluster::Vertex &closestVertexJ)
Given a pair of pointing clusters, receive the closest or farthest pair of vertices.
TFile f
Definition: plotHisto.C:6
Header file for the geometry helper class.
static void GetClusterBoundingBox(const pandora::Cluster *const pCluster, pandora::CartesianVector &minimumCoordinate, pandora::CartesianVector &maximumCoordinate)
Get minimum and maximum X, Y and Z positions of the calo hits in a cluster.
void MatchThreeViews(const pandora::ClusterVector &clusterVectorU, const pandora::ClusterVector &clusterVectorV, const pandora::ClusterVector &clusterVectorW, const ClusterAssociationMap &clusterAssociationMapUV, const ClusterAssociationMap &clusterAssociationMapVW, const ClusterAssociationMap &clusterAssociationMapWU, ParticleList &particleList) const
Create candidate particles using three primary clusters.
pandora::StatusCode GetAvailableClusters(const std::string &inputClusterListName, pandora::ClusterVector &clusterVector) const
Get a vector of available clusters.
Header file for the cluster helper class.
const Vertex & GetOuterVertex() const
Get the outer vertex.
const Vertex & GetInnerVertex() const
Get the inner vertex.
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
static float GetWirePitch(const pandora::Pandora &pandora, const pandora::HitType view, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
void SelectCleanClusters(const pandora::ClusterVector &inputVector, pandora::ClusterVector &outputVector) const
Select a set of clusters judged to be clean.
std::unordered_map< const pandora::Cluster *, TwoDSlidingFitResult > TwoDSlidingFitResultMap
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
bool IsInnerVertex() const
Is this the inner vertex.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
void MatchViews(const pandora::ClusterVector &clusterVector1, const pandora::ClusterVector &clusterVector2, const TwoDSlidingFitResultMap &slidingFitResultMap, ClusterAssociationMap &clusterAssociationMap) const
Match a pair of cluster vectors and populate the cluster association map.
void MergeClusters(const pandora::ClusterList &inputClusterList, pandora::ClusterList &outputClusterList) const
Merge broken clusters into a single cluster.
pandora::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
const pandora::CartesianVector & GetPosition() const
Get the vertex position.
static void GetCommonDaughterVolumes(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2, UIntSet &intersect)
Return the set of common daughter volumes between two 2D clusters.
Header file for the cosmic ray longitudinal track recovery algorithm class.