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